When I see the same question pop up twice in a week, I know it’s something worth diving into. Add into the mix that it relates to one of my favorite topics, RESTCONF, and it was an obvious choice for an Ask Hank blog post.
I got this question over on Twitter from a Guille who identifies as a “DevNet student” (aren’t we all).
“Quick question, how can I build the RESTCONF url when there are two identifiers?”
In this context, “identifiers” refer to the keys defined in YANG for a list.
Before we dive into the answer, let’s make sure we understand the question.
Crafting RESTCONF URLs for a specific element of a list
Going back to my tried and true YANG model for learning, ietf-interfaces.yang, we can see see that every “interface” is uniquely identified by it’s “name”
pyang -f tree --tree-path /interfaces/interface ietf-interfaces.yang module: ietf-interfaces +--rw interfaces +--rw interface* [name] +--rw name string +--rw description? string +--rw type identityref +--rw enabled? boolean +--rw link-up-down-trap-enable? enumeration {if-mib}?
The square brackets around the leaf indicate that it is the key. This is configured in the YANG model itself like this. (Note: the YANG model below has been edited for brevity. You can see the full YANG model on GitHub)
container interfaces { description "Interface parameters."; list interface { key "name"; description "The list of interfaces on the device."; leaf name { type string; description "The name of the interface." }
So how do we use this information with RESTCONF to craft a URL? I think an example is the way to go.
curl 'https://sandbox-iosxe-latest-1.cisco.com/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2' \ --header 'Accept: application/yang-data+json' \ --user developer:C1sco12345 { "ietf-interfaces:interface": { "name": "GigabitEthernet2", "description": "Configured by RESTCONF", "type": "iana-if-type:ethernetCsmacd", "enabled": true, "ietf-ip:ipv4": { "address": [ { "ip": "10.255.255.2", "netmask": "255.255.255.0" } ] }, "ietf-ip:ipv6": { } } }
What we have above shows that an equals sign followed by the value of the key you are interest in is used in the URL. Pretty straightforward.
But what about lists with more than one key?
So now we find ourselves at the question. What if you’ve got a list with more than one key? Many lists will have a single key, but let’s consider this example from the IOS XE Native models related to route lists.
pyang -f tree --tree-path=/native/ip/route Cisco-IOS-XE-native.yang module: Cisco-IOS-XE-native +--rw native +--rw ip +--rw route +--rw ip-route-interface-forwarding-list* [prefix mask] | +--rw prefix inet:ipv4-address | +--rw mask inet:ipv4-address | +--rw dhcp? empty | +--rw metric? uint8 | +--rw fwd-list* [fwd] | | +--rw fwd union | | +--rw interface-next-hop* [ip-address] | | | +--rw ip-address inet:ipv4-address
If you think logically, an entry in a routing table requires both the prefix and mask to be uniquely identified. This is because you could configured the following on a router:
ip route 192.168.100.0 255.255.255.0 10.10.10.1 ip route 192.168.100.0 255.255.255.224 172.16.32.1
Here the prefix of “192.168.100.0” is used with two different routes, but one route has a longer-mask. The YANG model reflects this need to capture both prefix and mask for a unique list element.
But how is this reflected in the RESTCONF URL? It is times like this, when I turn to the documentation. Which for RESTCONF means RFC8040.
Section 3.5.3. Encoding Data Resource Identifiers in the Request URI gives us the information we need.
o If there is only one key leaf value, the path segment is
constructed by having the list name, followed by an “=” character,
followed by the single key leaf value.
o If there are multiple key leaf values, the path segment is
constructed by having the list name, followed by the value of each
leaf identified in the “key” statement, encoded in the order
specified in the YANG “key” statement. Each key leaf value except
the last one is followed by a comma character.
While I find the RFCs great resources, they can be tough to read directly. But their examples are golden
Examples: container top { list list1 { key "key1 key2 key3"; ... list list2 { key "key4 key5"; ... leaf X { type string; } } } leaf-list Y { type uint32; } } For the above YANG definition, the container "top" is defined in the "example-top" YANG module, and a target resource URI for leaf "X" would be encoded as follows: /restconf/data/example-top:top/list1=key1,key2,key3
The key (pun intended) part of how this works is the comma. You simply common separate the key values in the URL. Applying this to our routing model above:
curl 'https://sandbox-iosxe-latest-1.cisco.com/restconf/data/Cisco-IOS-XE-native:native/ip/route/ip-route-interface-forwarding-list=1.1.1.0,255.255.255.0' \ --header 'Accept: application/yang-data+json' \ --user developer:C1sco12345 { "Cisco-IOS-XE-native:ip-route-interface-forwarding-list": { "prefix": "1.1.1.0", "mask": "255.255.255.0", "fwd-list": [ { "fwd": "10.10.20.253" } ] } }
Summary
Well, that’s about it, and I hope it helps better demystify RESTCONF use for everyone. If you’d like to continue digging into RESTCONF, I’d suggest checking out the other blogs in the Ask Hank series. Several have touched on model driven programmability topics, in fact the first one was about creating RESTCONF URLs. And of course, the examples in this post used one of the DevNet Always On Sandboxes. Feel free to explore RESTCONF with this great, free resource, available to everyone – even YOU! There are also Learning Labs and videos that dig into RESTCONF you can explore while you are at it.
If you’ve got a question you’d like to “Ask Hank”, let me know if the comments, email (hapresto@cisco.com), or over on twitter (@hfpreston). Until next time.
We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social!
Twitter @CiscoDevNet | Facebook | LinkedIn
Visit the new Developer Video Channel
CONNECT WITH US