Back when I started diving into studying for the Cisco DevNet certifications, I thought a lot of the REST API stuff was fairly easy. But I always struggled a bit with wrapping my head around YANG models & how exactly NETCONF/RESTCONF worked. A lot of it seemed more abstract, and browsing through YANG models isn't quite as intuitive as most REST API documentation.
These days I end up working quite a bit with NETCONF - and if there's one tool that's helped me more than anything, it's certainly YANG suite. So in this post, I wanted to spend a little bit of time walking through how to get set up with this tool - and walk through a quick example of how it can be used.
What's YANG Suite?
To put it simply: YANG Suite is a web-based tool that allows you to easily browse through YANG models & find what you need. It also has a bunch of tools to run test queries against devices, which makes developing NETCONF automation easier. It can also auto-generate code snippets - and who doesn't like that? 😄
YANG suite is an open source tool maintained by Cisco & the GitHub repo here.
Initial Setup
YANG suite is a containerized application, so we'll need a container host to run it on. You could use something like Docker Desktop to run it on your local PC, but I'll be using a dedicated Ubuntu machine in my lab with Docker installed.
Note: YANG suite now supports a local Python pip-based install. Check out the GitHub repo for more info on that.
Deploy with Docker
First thing we'll do is pull down the code from GitHub:
matt@yangsuite:~/yangsuite/docker$ git clone https://github.com/CiscoDevNet/yangsuite.git
Next, we can execute the setup script to help provision the YANG Suite containers, which is located at yangsuite/docker/start_yang_suite.sh
. The script will prompt you to set up an admin user and generate self-signed certificates:
matt@yangsuite:~/yangsuite/docker$ cd yangsuite/docker
matt@yangsuite:~/yangsuite/docker$ ./start_yang_suite.sh
Hello, please setup YANG Suite admin user.
username: matt
password:
confirm password:
email: [email protected]
Setup test certificates? (y/n): y
-- output omitted --
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]: US
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Certificates generated...
Building docker containers...
Once all of the above info is provided, the script will build the YANG Suite contianer images & launch them. However, by default it will launch in the foreground - so we can kill the script with Ctrl-C
& relaunch the containers with docker-compose up -d
.
Allow Access from Remote IPs
We may need to make a quick change depending on how we'll be accessing YANG Suite.
By default, YANG Suite will only permit access to the web UI from localhost
- so if you're running Docker on your local PC, then no change is necessary.
However, if you're running Docker on a dedicated VM like I am, then we'll need to allow external IPs to access the YANG Suite UI. This is controlled by the DJANGO_ALLOWED_HOSTS
environment variable that gets supplied to the container.
As long as we've already run the setup script once - our environment variables will be saved to yangsuite/docker/yangsuite/setup.env
:
DJANGO_SETTINGS_MODULE=yangsuite.settings.production
MEDIA_ROOT=/ys-data/
STATIC_ROOT=/ys-static/
DJANGO_STATIC_ROOT=/ys-static/
DJANGO_ALLOWED_HOSTS=localhost
YS_ADMIN_USER=<removed>
YS_ADMIN_PASS=<removed>
YS_ADMIN_EMAIL=<removed>
We'll need to change DJANGO_ALLOWED_HOSTS=localhost
to the IP address of the Docker host. So if your Docker host is reachable at 192.168.1.1
, then we'll set: DJANGO_ALLOWED_HOSTS=192.168.1.1
.
After which, we can bring up the containers again with docker-compose up -d
:
matt@yangsuite:~/yangsuite/docker$ docker-compose up -d
Recreating docker-yangsuite-1 ... done
Recreating docker-backup-1 ... done
Recreating docker-nginx-1 ... done
Once everything is running, the web UI can be reached at https://<ip address>:8443
.
Loading YANG Models
After we get logged in, we'll need to load the appropriate YANG models for whatever devices we're using.
For example, I'll be using Cisco IOS-XE devices running version 17.6.x code - so I'll need to download the YANG models from: https://github.com/YangModels/yang/tree/main/vendor/cisco/xe/1761
.
Within YANG Suite, we'll navigate to Setup > YANG files and repositories. Then click the button to add a New repository:
You can name the repo whatever you like. In my case, I named it ios-xe-1761
which describes the models it will hold.
Next we can tell YANG Suite where we want to pull our models from. There are a couple of options, including a direct upload from your local PC or querying models directly from a device - but I'll choose Git
.
After which, we'll need to fill in the following info:
The Repository URL will be the base Git repo that we're pulling from. In this case, that's https://github.com/YangModels/yang.git
.
We'll also need to specify which Git branch to pull from, which for the YangModels repo will be main
.
Then we'll specify which directory to import. The YangModels repository holds models for a large number of vendors & devices - so we only want to pull in what is necessary. In my case, I've set this to vendor/cisco/xe/1761
- which will only pull in the YANG models for Cisco IOS-XE 17.6.x devices. I've also checked the box for Include subdirectories.
Once that's all set, we can hit Import YANG files. Depending on how many models are being downloaded & how quick your Docker host is, this may take a few minutes.
After it finishes, mine displayed a message showing that 827 models had been added:
Selecting YANG Module Sets
Once we have all of our models downloaded into YANG Suite, it's time to set up some module sets. You can think of these as filters for the YANG models.
For example, later on we'll show how to change a wireless PSK with NETCONF. So since I already know what type of information I'll be working with, I can create a module set to only contain those models.
YANG Suite will require at least one module set to be configured, even if you don't want to filter anything out.
To do this, we'll navigate to Setup > YANG model sets. Then click New YANG set:
Again, since we'll be working with wireless data in a bit, I'll name my model set wireless
. We'll also have to select which YANG repository this will pull from, which will be ios-xe-1761
.
Next, we'll get to select which YANG models we want to include in our module set. To make things easy, I'll filter the models by wireless
and then click Add selected.
Once those are added, you'll likely see an error about missing dependencies. Some of the models we selected may have sub-models or data types that are located in other models.
In order to quickly add these, YANG Suite provides a one-click-button to Locate and add missing dependencies:
That's it - our model set is ready to use.
Adding Devices
Okay, so now that we have all of our necessary YANG models set up, let's take a add a device that we can use for testing. I'll be adding a Catalyst 9800 Wireless controller.
To do this, we'll head over to Setup > Device Profiles. Then click on Create new device.
Here we'll fill in a name for our device profile, along with the device's IP/FQDN and login credentials.
Scrolling down a bit, we'll also need to make sure we enable the appropriate management protocols. So I'll be checking the box for both NETCONF and RESTCONF, since I have both enabled. I'll also add SSH, which isn't shown in the screenshot below.
Please note, you'll likely want to check the box for Skip SSH key validation for this device under the NETCONF settings.
After that's all done, we can click Create Profile at the bottom.
Then, to validate everything works - we'll select our device & click the button for Check selected device's reachability.
With any luck, you should see a similar result as shown below:
Example: Changing Wireless PSK
Alright, now let's take a look at how we might use YANG Suite to test NETCONF / RESTCONF calls to a wireless controller.
In this example, perhaps we're developing automation to rotate the guest wireless network password on a regular basis. We need to figure out how specifically to accomplish that by finding the right YANG models & understanding what data is sent and received with those calls.
We'll explore how to do this with both NETCONF and RESTCONF.
Via NETCONF
To start off, we'll navigate to Protocols > NETCONF. On this page, we'll have full access to explore models, build XML payloads, and test them against our configured device.
Get-config
First thing we'll need is to select our YANG set & Modules. In my case, the YANG set will be wireless
, and I'll select the module: Cisco-IOS-XE-wireless-wlan-cfg
.
Then click the button to Load Modules:
By default, our NETCONF Operation will be set to get-config
, which will work for now since we only want to retrieve configuration and not change anything yet.
Under the Nodes pane, we can expand the tree a bit & dig in to find which call we need.
For our example, we'll need to examine the current configured WLAN profiles. So we'll check the box next to wlan-cfg-entries
:
This will retrieve all configured WLAN profiles on the controller. For now, let's do that so we can figure out what data we'll get back.
We can now click the button to Build RPC, and YANG Suite will automatically build the appropriate XML payload for us:
You'll also notice that I selected the catalyst 9800 as the target device. Let's go ahead and run this with the Run RPC(s) button, which should pop open a new window & establish a connection to our device.
We can see in the response above, that we have two WLAN profiles configured: test-lab-network
and test-guest-network
. For the purposes of this demo, I have opted to have the guest network PSK stored in plain text, so we can validate our changes more easily.
Okay, so what if we wanted to refine our query XML to only retrieve data on the test-guest-network
? Maybe we also want to filter our the additional information returned, and only see the current PSK?
Back on the payload editor, we can expand wlan-cfg-entries
and input our desired profile-name
:
We'll also find the psk
item further down in the list. Now we want to pull back this field, regardless of what the PSK is currently set to. So we'll click the value field, but leave it blank:
Once we click Build RPC, we can see our payload now shows the additional XML filters asking only for a single profile & it's associated PSK:
If we run that RPC call, we'll now see that we only get back a limited set of data:
Now we know exactly what payload to send if we want to get back the current configured PSK for any specific WLAN profile.
Let's try changing it!
Edit-config
Lucky for us, we're already nearly set up for that. We'll need to make two quick changes. First, set the NETCONF Operation to edit-config
:
Then, under the YANG tree, we'll set a new PSK:
Again, we'll click Build RPC - and take a quick look at the proposed change:
Look good to you? Okay, let's send it:
Sure enough, the new configuration was sent to the wireless controller and we got a response of: ok.
But of course, we can check quickly by switching our operation back to get-config
and re-running our previous XML payload:
Auto-generated snippets
Well if you're new to NETCONF, you might be asking yourself "Okay great, but how do I get this into Python?!?!"
YANG Suite has some built in tools to auto-generate Python code or Ansible playbooks, which can help us get started on our code more quickly.
To generate these, click the Replays button:
For example, I selected to auto-generate a Python script. Here's what that looks like:
#! /usr/bin/env python
import traceback
import lxml.etree as et
from argparse import ArgumentParser
from ncclient import manager
from ncclient.operations import RPCError
payload = [
'''
<get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<source>
<running/>
</source>
<filter>
<wlan-cfg-data xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-wireless-wlan-cfg">
<wlan-cfg-entries>
<wlan-cfg-entry>
<profile-name>test-guest-network</profile-name>
<psk/>
</wlan-cfg-entry>
</wlan-cfg-entries>
</wlan-cfg-data>
</filter>
</get-config>
''',
]
if __name__ == '__main__':
parser = ArgumentParser(description='Usage:')
# script arguments
parser.add_argument('-a', '--host', type=str, required=True,
help="Device IP address or Hostname")
parser.add_argument('-u', '--username', type=str, required=True,
help="Device Username (netconf agent username)")
parser.add_argument('-p', '--password', type=str, required=True,
help="Device Password (netconf agent password)")
parser.add_argument('--port', type=int, default=830,
help="Netconf agent port")
args = parser.parse_args()
# connect to netconf agent
with manager.connect(host=args.host,
port=args.port,
username=args.username,
password=args.password,
timeout=90,
hostkey_verify=False,
device_params={'name': 'csr'}) as m:
# execute netconf operation
for rpc in payload:
try:
response = m.dispatch(et.fromstring(rpc))
data = response.xml
except RPCError as e:
data = e.xml
pass
except Exception as e:
traceback.print_exc()
exit(1)
# beautify output
if et.iselement(data):
data = et.tostring(data, pretty_print=True).decode()
try:
out = et.tostring(
et.fromstring(data.encode('utf-8')),
pretty_print=True
).decode()
except Exception as e:
traceback.print_exc()
exit(1)
print(out)
Via RESTCONF
What if we prefer working with REST & JSON instead of XML? This time we'll navigate to Protocols > RESTCONF.
Here, we'll select our YANG set & modules again. In case you skipped the NETCONF section, we're working with the wireless
YANG set & the Cisco-IOS-XE-wireless-wlan-cfg
module.
We'll also select a device to use, then click Load Module(s):
Again, we'll see a similar structure to the NETCONF side. But this time, we'll utilize it quite a bit differently.
In the screenshot above, I've already selected the wlan-cfg-entries
entry. Next, we'll click the button to Generate API(s):
We'll see auto-generated API documentation for all of the available calls. This list will contain every variation possible, so it can be quite long. Since we already went through the NETCONF method, we know what data we need to find / use which should make this easier.
To start with, I'll expand the GET for /data/Cisco-IOS-XE-wireless-wlan-cfg:wlan-cfg-data/wlan-cfg-entries
. We'll have the ability to test the RESTCONF calls directly from this interface as well by clicking on Try it out:
In the screenshot above, I've already submitted the test request & gotten a response from the controller. While the screenshot is cut off a bit, we can see both of our wireless profile names.
If we wanted to see only the PSK, like we did with our previous example - we could scroll down quite a bit to find the GET request for /data/Cisco-IOS-XE-wireless-wlan-cfg:wlan-cfg-data/wlan-cfg-entries/wlan-cfg-entry={wlan-cfg-entry-profile-name}/psk
In the screenshot below, I've already input our test-guest-network
profile name & executed the API call:
Sure enough, we see the PSK that we had just configured via NETCONF a few minutes ago.
Now let's change it. We'll expand the PATCH API call for the same endpoint, and fill in the request body with our new PSK:
Executing that call, the wireless controller returned a status code of 204.
So let's check again to see if that updated properly:
Now that we have all the appropriate REST calls, it should be much easier to start developing our automation.
Okay, I think that's about all I wanted to cover in this post. I've seen a lot of people struggle with NETCONF much like I used to, and I think the real key to getting familiar is just having the right tools & spending enough time with it. YANG Suite has really helped me get more familiar with the various model structures and how to use them.
Hopefully this information helps others to get started. NETCONF & YANG are certainly big hills to climb, but the right tools can make all the difference.