Help us improve your experience.

Let us know what you think.

Do you have time for a two-minute survey?

header-navigation
keyboard_arrow_up
close
keyboard_arrow_left
Junos PyEZ Developer Guide
Table of Contents Expand all
list Table of Contents
file_download PDF
{ "lLangCode": "en", "lName": "English", "lCountryCode": "us", "transcode": "en_US" }
English
keyboard_arrow_right

Use Junos PyEZ to Execute RPCs on Junos Devices

date_range 10-May-24

Use the Device rpc property to execute operational RPCs on Junos devices.

You can use Junos PyEZ to execute remote procedure calls (RPCs) on demand on Junos devices. After creating an instance of the Device class, you can execute RPCs as a property of the Device instance. You can perform most of the same operational commands using Junos PyEZ that you can execute in the CLI.

The Junos XML API is an XML representation of Junos OS configuration statements and operational mode commands. It defines an XML equivalent for all statements in the Junos OS configuration hierarchy and many of the commands that you issue in CLI operational mode. Each operational mode command with a Junos XML counterpart maps to a request tag element and, if necessary, a response tag element. Request tags are used in RPCs within NETCONF or Junos XML protocol sessions to request information from a Junos device. The server returns the response using Junos XML elements enclosed within the response tag element.

When you use Junos PyEZ to execute RPCs, you map the request tag name to a method name. This topic outlines how to map CLI commands to Junos PyEZ RPCs, how to execute RPCs using Junos PyEZ, and how to customize the data returned in the RPC reply.

Map Junos OS Commands to Junos PyEZ RPCs

All operational commands that have Junos XML counterparts are listed in the Junos XML API Explorer. You can also display the Junos XML request tag element for any operational mode command that has a Junos XML counterpart either on the CLI or using Junos PyEZ. Once you obtain the request tag, you can map it to the Junos PyEZ RPC method name.

To display the Junos XML request tag for a command in the CLI, include the | display xml rpc option after the command. The following example displays the request tag for the show route command:

content_copy zoom_out_map
user@router> show route | display xml rpc 
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1R1/junos">
    <rpc>
        <get-route-information>
        </get-route-information>
    </rpc>
</rpc-reply>

You can also display the Junos XML request tag for a command using Junos PyEZ. To display the request tag, call the Device instance display_xml_rpc() method, and include the command string and format='text' as arguments. For example:

content_copy zoom_out_map
from jnpr.junos import Device

with Device(host='router.example.com') as dev:   
    print (dev.display_xml_rpc('show route', format='text'))

Executing the program returns the request tag for the show route command.

content_copy zoom_out_map
<get-route-information>
</get-route-information>

You can map the request tags for an operational command to a Junos PyEZ RPC method name. To derive the RPC method name, replace any hyphens in the request tag with underscores (_) and remove the enclosing angle brackets. For example, the <get-route-information> request tag maps to the get_route_information() method name.

Execute RPCs as a Property of the Device Instance

Each instance of Device has an rpc property that enables you to execute any RPC available through the Junos XML API. In a Junos PyEZ application, after establishing a connection with the device, you can execute the RPC by appending the rpc property and RPC method name to the device instance as shown in the following example:

content_copy zoom_out_map
from jnpr.junos import Device
from lxml import etree

with Device(host='dc1a.example.com') as dev:   
    #invoke the RPC equivalent to "show version"
    sw = dev.rpc.get_software_information()
    print(etree.tostring(sw, encoding='unicode'))

The return value is an XML object starting at the first element under the <rpc-reply> tag. In this case, the get_software_information() RPC returns the <software-information> element.

content_copy zoom_out_map
<software-information>
<host-name>dc1a</host-name>
...
</software-information>

Junos OS commands can have fixed-form options that do not have a value. For example, the Junos XML equivalent for the show interfaces terse command indicates that terse is an empty element.

content_copy zoom_out_map
user@router> show interfaces terse | display xml rpc
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/14.1R1/junos">
    <rpc>
        <get-interface-information>
            <terse/>
        </get-interface-information>
    </rpc>
</rpc-reply>

To execute an RPC and include a command option that does not take a value, add the option to the RPC method’s argument list, change any dashes in the option name to underscores, and set it equal to True. The following code executes the Junos PyEZ RPC equivalent of the show interfaces terse command:

content_copy zoom_out_map
rsp = dev.rpc.get_interface_information(terse=True)

Junos OS commands can also have options that require a value. For example, in the following output, the interface-name element requires a value, which is the name of the interface for which you want to return information:

content_copy zoom_out_map
user@router> show interfaces ge-0/0/0 | display xml rpc
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/14.1R1/junos">
    <rpc>
        <get-interface-information>
            <interface-name>ge-0/0/0</interface-name>
        </get-interface-information>
    </rpc>
</rpc-reply>

To execute an RPC and include a command option that requires a value, add the option to the RPC method’s argument list, change any dashes in the option name to underscores, and then set it equal to the appropriate value. The following example executes the Junos PyEZ RPC equivalent of the show interfaces ge-0/0/0 command:

content_copy zoom_out_map
rsp = dev.rpc.get_interface_information(interface_name='ge-0/0/0')

Specify the Format of the RPC Output

By default, the RPC return value is an XML object starting at the first element under the <rpc-reply> tag. You can also return the RPC output in text or JavaScript Object Notation (JSON) format by including either the {'format':'text'} or {'format':'json'} dictionary as the RPC method’s first argument.

Note:

RPC output in JSON format is supported starting in Junos OS Release 14.2R1.

The following example returns the output of the get_software_information() RPC in text format, which is identical to the output emitted for the show version command in the CLI, except that the RPC output is enclosed within an <output> element.

content_copy zoom_out_map
from jnpr.junos import Device
from lxml import etree  
    
with Device(host='router1.example.com') as dev:      
    sw_info_text = dev.rpc.get_software_information({'format':'text'})
    print(etree.tostring(sw_info_text))  
content_copy zoom_out_map
user@server:~$ python3 junos-pyez-rpc-text-format.py

<output>
Hostname: router1
Model: mx104
Junos: 18.3R1.9
JUNOS Base OS boot [18.3R1.9]
JUNOS Base OS Software Suite [18.3R1.9]
JUNOS Crypto Software Suite [18.3R1.9]
JUNOS Packet Forwarding Engine Support (TRIO) [18.3R1.9]
JUNOS Web Management [18.3R1.9]
JUNOS Online Documentation [18.3R1.9]
JUNOS SDN Software Suite [18.3R1.9]
JUNOS Services Application Level Gateways [18.3R1.9]
JUNOS Services COS [18.3R1.9]
JUNOS Services Jflow Container package [18.3R1.9]
JUNOS Services Stateful Firewall [18.3R1.9]
JUNOS Services NAT [18.3R1.9]
JUNOS Services RPM [18.3R1.9]
JUNOS Services Captive Portal and Content Delivery Container package [18.3R1.9]
JUNOS Macsec Software Suite [18.3R1.9]
JUNOS Services Crypto [18.3R1.9]
JUNOS Services IPSec [18.3R1.9]
JUNOS DP Crypto Software Software Suite [18.3R1.9]
JUNOS py-base-powerpc [18.3R1.9]
JUNOS py-extensions-powerpc [18.3R1.9]
JUNOS jsd [powerpc-18.3R1.9-jet-1]
JUNOS Kernel Software Suite [18.3R1.9]
JUNOS Routing Software Suite [18.3R1.9]
<output>

The following example returns the output of the get_software_information() RPC in JSON format.

content_copy zoom_out_map
from jnpr.junos import Device
from pprint import pprint

with Device(host='router1.example.com') as dev:      
    sw_info_json = dev.rpc.get_software_information({'format':'json'})
    pprint(sw_info_json)
content_copy zoom_out_map
user@server:~$ python3 junos-pyez-rpc-json-format.py
{u'software-information': [{u'host-name': [{u'data': u'router1'}],
                            u'junos-version': [{u'data': u'18.3R1.9'}],
                            u'package-information': [{u'comment': [{u'data': u'JUNOS Base OS boot [18.3R1.9]'}],
                                                      u'name': [{u'data': u'junos'}]},
                                                     {u'comment': [{u'data': u'JUNOS Base OS Software Suite [18.3R1.9]'}],
                                                      u'name': [{u'data': u'jbase'}]},
...

Specify the Scope of Data to Return

You can use Junos PyEZ to execute an RPC to retrieve operational information from Junos devices. Starting in Junos PyEZ Release 2.3.0, when you request XML output, you can filter the reply to return only specific elements. Filtering the output is beneficial when you have extensive operational output, but you only need to work with a subset of the data.

To filter the RPC reply to return only specific tags, include the RPC method’s filter_xml argument. The filter_xml parameter takes a string containing the subtree filter that selects the elements to return. The subtree filter returns the data that matches the selection criteria.

The following Junos PyEZ example executes the <get-interface-information> RPC and filters the output to retrieve just the <name> element for each <physical-interface> element in the reply:

content_copy zoom_out_map
from jnpr.junos import Device
from lxml import etree

with Device(host='router.example.com', use_filter=True) as dev:
    filter = '<interface-information><physical-interface><name/></physical-interface></interface-information>'
    result = dev.rpc.get_interface_information(filter_xml=filter)
    print (etree.tostring(result, encoding='unicode'))

When you execute the script, it displays each physical interface’s name element.

content_copy zoom_out_map
user@server:~$ python3 junos-pyez-get-interface-names.py
<interface-information style="normal"><physical-interface><name>
lc-0/0/0
</name></physical-interface><physical-interface><name>
pfe-0/0/0
</name></physical-interface><physical-interface><name>
pfh-0/0/0
</name></physical-interface><physical-interface><name>
xe-0/0/0
</name></physical-interface><physical-interface><name>
xe-0/1/0
</name></physical-interface><physical-interface><name>
ge-1/0/0
</name></physical-interface>
...
</interface-information>

Specify the RPC Timeout

RPC execution time can vary considerably depending on the RPC and the device. By default, NETCONF RPCs time out after 30 seconds. You can extend the timeout value by including the dev_timeout=seconds argument when you execute the RPC to ensure that the RPC does not time out during execution. dev_timeout adjusts the device timeout only for that single RPC operation.

content_copy zoom_out_map
dev.rpc.get_route_information(table='inet.0', dev_timeout=55)

Normalize the XML RPC Reply

When you execute an RPC, the RPC reply can include data that is wrapped in newlines or contains other superfluous whitespace. Unnecessary whitespace can make it difficult to parse the XML and find information using text-based searches. You can normalize an RPC reply, which strips out all leading and trailing whitespace and replaces sequences of internal whitespace characters with a single space.

Table 1 compares a default RPC reply to the normalized version. The default RPC reply includes many newlines that are not present in the normalized reply.

Table 1: Comparison of a Default and Normalized RPC Reply

Default RPC Reply

Normalized RPC Reply

<interface-information style="terse">
<logical-interface>
<name>\nge-0/0/0.0\n</name>
<admin-status>\nup\n</admin-status>
<oper-status>\nup\n</oper-status>
<filter-information>\n</filter-information>
<address-family>
<address-family-name>\ninet\n</address-family-name>
<interface-address>
<ifa-local emit="emit">\n198.51.100.1/24\n</ifa-local>
</interface-address>
</address-family>
</logical-interface>
</interface-information>
<interface-information style="terse">
<logical-interface>
<name>ge-0/0/0.0</name>
<admin-status>up</admin-status>
<oper-status>up</oper-status>
<filter-information/>
<address-family>
<address-family-name>inet</address-family-name>
<interface-address>
<ifa-local emit="emit">198.51.100.1/24</ifa-local>
</interface-address>
</address-family>
</logical-interface>
</interface-information>

You can enable normalization for the duration of a session with a device, or you can normalize an individual RPC reply when you execute the RPC. To enable normalization for the entire device session, include normalize=True in the argument list either when you create the device instance or when you connect to the device using the open() method.

content_copy zoom_out_map
dev = Device(host='router1.example.com', user='root', normalize=True)

# or 

dev.open(normalize=True)

To normalize an individual RPC reply, include normalize=True in the argument list for that RPC method.

content_copy zoom_out_map
dev.rpc.rpc_method(normalize=True)

For example:

content_copy zoom_out_map
rsp = dev.rpc.get_interface_information(interface_name='ge-0/0/0.0', terse=True, normalize=True)

If you do not normalize the RPC reply, you must account for any whitespace when using XPath expressions that reference a specific node or value. The following example selects the IPv4 address for a logical interface. In the XPath expression, the predicate specifying the inet family must account for the additional whitespace in order for the search to succeed. The resulting value includes leading and trailing newlines.

content_copy zoom_out_map
rsp = dev.rpc.get_interface_information(interface_name='ge-0/0/0.0', terse=True)
print (rsp.xpath('.// \
    address-family[normalize-space(address-family-name)="inet"]/ \
    interface-address/ifa-local')[0].text)
content_copy zoom_out_map
'\n198.51.100.1/24\n'

When you normalize the RPC reply, any leading and trailing whitespace is removed, which makes text-based searches much more straightforward.

content_copy zoom_out_map
rsp = dev.rpc.get_interface_information(interface_name='ge-0/0/0.0', terse=True, normalize=True)
print (rsp.xpath('.//address-family[address-family-name="inet"]/ \
    interface-address/ifa-local')[0].text)
content_copy zoom_out_map
'198.51.100.1/24'
footer-navigation