Getting XML data sample for a given leaf in a YANG model#
We can praise YANG as long as we want, but for an end user YANG is useful as the tooling around it and the applications leveraging it. Ask yourself, as a user of any kind of NETCONF/YANG application what was the last time you looked at a *.yang
file content and found something that was needed to consume that application?
In a user role I personally never look at a YANG source, though, I look at the tree or HTML representation of YANG all the time; Thats is the YANG human interface for me.
And even in these human friendly formats you can't find all the answers; for example, looking at the YANG tree, how do you get the XML data sample of a given leaf? Thats what we will discover in this post.
Problem statement#
Getting the XML data sample of a given leaf? What is this, why might I need it?
Lets work through a real-life example that should make a perfect point. Suppose you need to get a list of configured users from a given network element (NE). You would normally do this by leveraging <get-config>
operation, but in order to get only the users portion of the configuration, you would need to augment your request with a filter.
NETCONF defaults to subtree filtering when it comes to filters.
<!-- subtree filter example from RFC6241 -->
<rpc message-id="101"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-config>
<source>
<running/>
</source>
<filter type="subtree">
<top xmlns="http://example.com/schema/1.2/config">
<users/>
</top>
</filter>
</get-config>
</rpc>
Now the question comes: how do one know how to craft the subtree filter XML data for a given NE? If you will send the above XML envelope to any NE you will receive an error, because the subtree filter provided is not how the users are modelled in the underlying YANG model.
Yes, it boils down to an underlying model used by a given NE; you would need to consult with this model and derive the right nodes to get to the configuration block in question.
Actually, that post is a feedback to the question that popped up in my twitter recently:
Hello @nickrusso42518 @ntdvps whats the best way to transform a YANG file/section into a XML filter to use in a NETCONF get message? I used to export YANG file with pyang to html format, but it bothers me put the exact tree by hand. Are there an easy way?
— Rafael Ganascim (@rganascim) January 31, 2020
Solving the problem with PYANG#
Rafael asked a very practical question that every NETCONF user encounters; ours example follows the same question by asking how do I know which XML data to use in my subtree filter to get users config, are there aby tools for that?
It didn't take Rafael long to come up with a solution to his own question, which he explained in the same thread:
I found an "easy" way to get the xml tree, instead of writing by hand
— Rafael Ganascim (@rganascim) January 31, 2020
As you can see, he leveraged PYANG and solved the problem with a grain of sed
salt. The steps he took can be categorized with 4 major steps:
- Generated HTML view of a YANG model (jstree output format)
- Copy the path of a node in question
- Remove the prefix from that path
- Generate XML skeleton data for that cleaned path
Lets solve our example question following this method and using Nokia SR OS router running 19.10.r2.
First, lets enjoy the generated HTML views of Nokia SR OS models provided in the nokia-yangtree repo, no need to generate anything yourself, we value your time and here we got you covered.
Few clicks away and you drill down to the user
list of the configuration model. Thats where our configured local users live.
To our grief, PYANG cant digest the path that it produces in its Path column of the HTML view, therefore we need to sanitize it and remove the path prefix (conf
in our case) from it:
# path in the HTML: /conf:configure/conf:system/conf:security/conf:user-params/conf:local-user/conf:user
/configure/system/security/user-params/local-user/user
SR OS PRO TIP that makes competition angry
You can get the model path right out from the box when you navigate to the context of interest
*(ex)[]
A:admin@R1# configure system security user-params local-user user del
*(ex)[configure system security user-params local-user user "del"]
A:admin@R1# pwc model-path
Present Working Context:
/nokia-conf:configure/system/security/user-params/local-user/user=del
Now all you need is to copy that path and remove the user key.
Having the model path without the context we can generate the XML data using the sample-xml-skeleton
output of PYANG.
For that step I leverage the open YANG models of SR OS that you can download from the 7x50_YANG_MODELS repo and the PYANG tool in a container:
$ docker run --rm -v $(pwd):/yang hellt/pyang pyang -f sample-xml-skeleton --sample-xml-skeleton-path "/configure/system/security/user-params/local-user/user" nokia-conf-combined.yang
<?xml version='1.0' encoding='UTF-8'?>
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
<system>
<security>
<user-params>
<local-user>
<user>
<user-name/>
<home-directory/>
<password/>
<cli-engine>
<!-- # entries: 0..2 -->
</cli-engine>
<!-- <<SNIP>> -->
</user>
</local-user>
</user-params>
</security>
</system>
</configure>
</data>
Pretty neat, right? You have the path to the node you specified as well as all the enclosed containers, lists and leafs so you can filter on them.
In our case we can cut everything that sits under the <user>
node and get the portion of XML data that is ready to be filled in a subtree filter:
<!-- this data is ready to be pasted in a subtree template -->
<configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
<system>
<security>
<user-params>
<local-user>
<user>
</user>
</local-user>
</user-params>
</security>
</system>
</configure>
</data>
This is a get-config
template XML envelope:
<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="getBGPNBRstate" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get>
<filter>
</filter>
</get>
</rpc>
Just paste it in the get-config
XML envelope like this and save it in a get-users.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="getBGPNBRstate" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get>
<filter>
<configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
<system>
<security>
<user-params>
<local-user>
<user>
</user>
</local-user>
</user-params>
</security>
</system>
</configure>
</filter>
</get>
</rpc>
Now its ready to be tested (using netconf-console in a docker container):
[root@infra ~]# docker run -it --rm -v $(pwd):/rpcs hellt/netconf-console --host=10.1.0.11 --port=830 -u admin -p admin /rpcs/get-users.xml
<?xml version='1.0' encoding='UTF-8'?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="getBGPNBRstate">
<data>
<configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
<system>
<security>
<user-params>
<local-user>
<user>
<user-name>admin</user-name>
<password>$2y$10$TQrZlpBDra86.qoexZUzQeBXDY1FcdDhGWdD9lLxMuFyPVSm0OGy6</password>
<cli-engine>md-cli</cli-engine>
<cli-engine>classic-cli</cli-engine>
<access>
<console>true</console>
<ftp>true</ftp>
<snmp>true</snmp>
<netconf>true</netconf>
<grpc>true</grpc>
</access>
<console>
<member>administrative</member>
<member>netconf</member>
</console>
</user>
</local-user>
</user-params>
</security>
</system>
</configure>
</data>
</rpc-reply>
Works!
Automating the solution#
Seeing this in action got me itching; I wanted to automate this process so it would be generic and less manual. For that reason I enriched my Pyang-docker tool with a tiny shell script that will:
- Automatically strip the path prefix from the string copied from HTML representation of a model
- Call pyang with the right flags to generate the xml data
Now when you copy-paster your model path from the HTML you can immediately get the XML data skeleton with:
$ docker run --rm -v $(pwd):/yang hellt/pyang xmlsk.sh "/conf:configure/conf:system/conf:security/conf:user-params/conf:local-user/conf:user/conf:user-name" nokia-conf-combined.yang
<?xml version='1.0' encoding='UTF-8'?>
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
<system>
<security>
<user-params>
<local-user>
<user>
<user-name/>
</user>
</local-user>
</user-params>
</security>
</system>
</configure>
</data>