Help us improve your experience.

Let us know what you think.

Do you have time for a two-minute survey?

Announcement: Try the Ask AI chatbot for answers to your technical questions about Juniper products and solutions.

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

Define Different Levels of Output in Custom YANG RPCs for Junos Devices

date_range 29-Nov-23

Defining Different Levels of Output in Custom YANG RPCs

You can define custom RPCs for Junos devices using YANG. The RPC output can be customized to emit different data and CLI formatting depending on the RPC input. This enables you to create different styles, or levels of output, for the same RPC.

You can request the desired style by including the appropriate value for the input argument when you invoke the RPC. The action script must process this argument and emit the XML output for the requested style. Junos OS then translates the XML into the corresponding CLI output defined for that style in the YANG module. The RPC template presented in this topic creates two styles: brief and detail.

To create different styles for the output of an RPC:

  1. In the YANG module that includes the RPC, import the Junos OS ODL extensions module, which defines YANG extensions that you use to precisely specify how to render the output when you execute the RPC’s command in the CLI or when you request the RPC output in text format.
    content_copy zoom_out_map
       import junos-extension-odl {
          prefix junos-odl;
       }
    Note:

    Starting in Junos OS Release 17.4R1, the Junos OS YANG modules use a new naming convention for the module’s name, filename, and namespace.

  2. In the RPC's input parameters, define a leaf statement with type enumeration, and include enum statements that define names for each style.
    content_copy zoom_out_map
       rpc rpc-name {
          description "RPC description";
          junos:command "cli-command" {
             junos:action-execute {
                junos:script "action-script-filename";
             }
          }
    
          input {
             leaf level {
                type enumeration {
                   enum brief {
                      description "Display brief output";
                   }
                   enum detail {
                      description "Display detailed output";
                   }
                }
             }
          }
       }
    Note:

    Starting in Junos OS Release 17.3, the action-execute statement is a substatement to command. In earlier releases, the action-execute and command statements are placed at the same level, and the command statement is optional.

  3. In the RPC output statement, create separate junos-odl:style statements that define the CLI formatting for each style. The identifier for each style statement should match one of the style names defined within the enumerated leaf statement.
    content_copy zoom_out_map
          output {
             container output-container {
    
                //  leaf definitions 
    
                junos-odl:style brief {
                   junos-odl:format output-container-format-brief {
                      // formatting for brief output
                   }
                }
                junos-odl:style detail {
                   junos-odl:format output-container-format-detail {
                      // formatting for detailed output
                   }
                }
    
             }
          }
    Note:

    Starting in Junos OS Release 17.3, the CLI formatting for a custom RPC is defined within the junos-odl:format extension statement, and junos-odl:format is a substatement to junos-odl:style. In earlier releases, the CLI formatting is defined using a container that includes the junos-odl:cli-format statement, and the junos-odl:style statement is included within that container.

  4. In the RPC’s action script, process the input argument, and emit the XML output for the requested style enclosed in a parent element that has a tag name identical to the style name.
    Note:

    Starting in Junos OS Release 21.2R1 and Junos OS Evolved Release 21.2R1, when the device passes command-line arguments to a Python action script, it prefixes a single hyphen (-) to single-character argument names and prefixes two hyphens (--) to multi-character argument names.

    content_copy zoom_out_map
    #!/usr/bin/python3
    # Junos OS Release 21.2R1 and later
    
    import argparse
    
    parser = argparse.ArgumentParser(description='This is a demo script.')
    parser.add_argument('--level', required=False, default='brief')
    parser.add_argument('--rpc_name', required=True)
    args = parser.parse_args()
    
    print ("<output-container>")     
    print ("<{}>".format(args.level))     # tag name is brief or detail
      
    if args.level == "brief":
       # print statements for brief output
       
    if args.level == "detail":
      # print statements for detailed output
    
    print ("</{}>".format(args.level))
    print ("</output-container>")
    

    See Example: Defining Different Levels of Output for full script examples that work in the various releases.

The following code outlines the general structure of the RPC and enclosing module. When you invoke the RPC in the CLI and include the input argument level and specify either brief or detail, Junos OS renders the output defined for that style.

content_copy zoom_out_map
module module-name {
   namespace "http://yang.juniper.net/yang/1.1/jrpc";
   prefix jrpc;

   import junos-extension {
      prefix junos;
   }
   import junos-extension-odl {
      prefix junos-odl;
   }

   organization
      "Juniper Networks, Inc.";
   description
      "Junos OS YANG module for custom RPCs";

   rpc rpc-name {
      description "RPC description";

      junos:command "cli-command" {
         junos:action-execute {
            junos:script "action-script-filename";
         }
      }

      input {
         leaf level {
            type enumeration {
               enum brief {
                  description "Display brief output";
               }
               enum detail {
                  description "Display detailed output";
               }
            }
         }
      }
      output {
         container output-container {

            // leaf definitions

            junos-odl:style brief {
               junos-odl:format output-container-format-brief {
                  // formatting for brief output
               }
            }

            junos-odl:style detail {
               junos-odl:format output-container-format-detail {
                  // formatting for detailed output
               }
            }

         }
      }
   }
}

To execute the RPC in the CLI, issue the command defined by the junos:command statement, and specify the style by including the appropriate command-line argument, which in this example is level. The corresponding action script processes the input argument and emits the output for the requested style.

content_copy zoom_out_map
user@host> cli-command level brief

Example: Defining Different Levels of Output

This example presents a simple custom YANG RPC and action script that determine if a host is reachable and print different levels of output depending on the user input.

Requirements

This example uses the following hardware and software components:

  • Device running Junos OS Release 17.3R1 or later that supports loading custom YANG data models.

Overview of the RPC and Action Script

The YANG module in this example defines a custom RPC to ping the specified host and return the result using different levels of output based on the user’s input. The YANG module rpc-style-test is saved in the rpc-style-test.yang file. The module imports the Junos OS extension modules, which provide the extensions required to execute custom RPCs on the device and to customize the CLI output.

The module defines the get-host-status RPC. The <get-host-status> request tag is used to remotely execute the RPC on the device. In the RPC definition, the junos:command statement defines the command that is used to execute the RPC in the CLI, which in this case is show host-status.

content_copy zoom_out_map
  rpc get-host-status {
     description "RPC example to retrieve host status";

     junos:command "show host-status" {
        junos:action-execute {
           junos:script "rpc-style-test.py";
        }
     }
    ...

The junos:action-execute and junos:script statements define the action script that is invoked when you execute the RPC. This example uses a Python action script named rpc-style-test.py to retrieve the information required by the RPC. The script returns the XML output elements for each level of output as defined in the RPC's output statement.

Note:

Starting in Junos OS Release 17.3, the action-execute statement is a substatement to command. In earlier releases, the action-execute and command statements are placed at the same level, and the command statement is optional.

The RPC has two input parameters, hostip and level. The hostip parameter is the host to check for reachability. The level parameter selects the style for the RPC's output. When you execute the RPC, you include the target host’s IP address and a level, brief or detail. The action script defines the default value for level as 'brief', so if you omit this argument, the RPC prints the output corresponding to the brief style.

content_copy zoom_out_map
     input {
        leaf hostip {
           description "Host IP address";
           type string;
        }
        leaf level {
           type enumeration {
              enum brief {
                 description "Display brief output";
              }
              enum detail {
                 description "Display detailed output";
              }
           }
        }
     }

The RPC also defines the output nodes that must be emitted by the corresponding action script. The root node is the <host-status-information> element, which encloses either the <brief> or the <detail> element, depending on the user input, along with the child output nodes specified for each level of output. Both levels of output include the <hostip> and <status> child elements, but the <detail> element also includes the <date> child element. The junos-odl:format statements define the formatting for the output that is displayed in the CLI. This node is not emitted in the output XML tree.

content_copy zoom_out_map
     output {
        container host-status-information {
           ...
           junos-odl:style brief {
              junos-odl:format host-status-information-format-brief {
                  ... 
              }
           }
           junos-odl:style detail {
              junos-odl:format host-status-information-format-detail {
                 ...
              }
           }
        }
     }

The action script pings the host to determine if it is reachable and sets the status based on the results. The script then constructs and prints the XML for the RPC output based on the specified level argument. The XML tree must exactly match the hierarchy defined in the RPC.

The module containing the RPC and the action script file are added to the device as part of a new YANG package named rpc-style-test.

YANG Module and Action Script

YANG Module

The YANG module, rpc-style-test.yang, defines the RPC, the command used to execute the RPC in the CLI, and the name of the action script to invoke when the RPC is executed. The base name of the file must match the module name.

content_copy zoom_out_map
/*
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*/

module rpc-style-test {
  namespace "http://yang.juniper.net/yang/1.1/jrpc";
  prefix jrpc;

  import junos-extension-odl {
    prefix junos-odl;
  }
  import junos-extension {
    prefix junos;
  }

  organization
    "Juniper Networks, Inc.";

  description
    "Junos OS YANG module for RPC example";

  rpc get-host-status {
     description "RPC example to retrieve host status";

     junos:command "show host-status" {
        junos:action-execute {
           junos:script "rpc-style-test.py";
        }
     }

     input {
        leaf hostip {
           description "Host IP address";
           type string;
        }
        leaf level {
           type enumeration {
              enum brief {
                 description "Display brief output";
              }
              enum detail {
                 description "Display detailed output";
              }
           }
        }
     }
     output {
        container host-status-information {
           leaf hostip {
              type string;
              description "Host IP";
           }
           leaf status {
              type string;
              description "Operational status";
           }
           leaf date {
              type string;
              description "Date information";
           }
           junos-odl:style brief {
              junos-odl:format host-status-information-format-brief {
                 junos-odl:header "Brief output\n";
                 junos-odl:picture "@<<<<<<<<<<<< @";
                 junos-odl:space;
                 junos-odl:line {
                   junos-odl:field "hostip";
                   junos-odl:field "status";
                 }
              }
           }
           junos-odl:style detail {
              junos-odl:format host-status-information-format-detail {
                 junos-odl:header "Detail output\n";
                 junos-odl:picture "@<<<<<<<<<<<<  @<<<<<<<<<<<< @";
                 junos-odl:space;
                 junos-odl:line {
                    junos-odl:field "hostip";
                    junos-odl:field "status";
                    junos-odl:field "date";
                 }
              }
           }
        }
     }
  }
}

Action Script

The corresponding action script is rpc-style-test.py. The action script prints different levels of output based on the value of the level argument provided by the user. The script defines a default value of 'brief' for the level argument so that if the user omits the argument, the script returns the brief style of output. This example provides two versions of the action script, which appropriately handle the script's command-line arguments for the different releases.

Action Script (Junos OS Release 21.2R1 and later)
content_copy zoom_out_map
#!/usr/bin/python3
# Junos OS Release 21.2R1 and later

import os
import argparse

parser = argparse.ArgumentParser(description='This is a demo script.')
parser.add_argument('--hostip', required=True)
parser.add_argument('--level', required=False, default='brief')
parser.add_argument('--rpc_name', required=True)
args = parser.parse_args()

f = os.popen('date')
now = f.read()

# Ping target host and set the status
response = os.system('ping -c 1 ' + args.hostip + ' > /dev/null')
if response == 0:
    pingstatus = "Host is Active"
else:
    pingstatus = "Host is Inactive"

# Print RPC XML for the given style
print ("<host-status-information>")
print ("<{}>".format(args.level))
print ("<hostip>{}</hostip>".format(args.hostip))
print ("<status>{}</status>".format(pingstatus))
if args.level == "detail":
    print ("<date>{}</date>".format(now))
print ("</{}>".format(args.level))
print ("</host-status-information>")
Action Script (Junos OS Release 21.1 and earlier)
content_copy zoom_out_map
#!/usr/bin/python
# Junos OS Release 21.1 and earlier

import sys
import os

args = {'hostip': None, 'level': 'brief'}

# Retrieve user input and store the values in the args dictionary
for arg in args.keys():
    if arg in sys.argv:
        index = sys.argv.index(arg)
        args[arg] = sys.argv[index+1]

f = os.popen('date')
now = f.read()

# Ping target host and set the status
if args['hostip'] is not None:
    response = os.system('ping -c 1 ' + args['hostip'] + ' > /dev/null')
    if response == 0:
        pingstatus = "Host is Active"
    else:
        pingstatus = "Host is Inactive"
else:
    pingstatus = "Invalid host"

# Print RPC XML for the given style
print ("<host-status-information>")
print ("<{}>".format(args['level']))
print ("<hostip>{}</hostip>".format(args['hostip']))
print ("<status>{}</status>".format(pingstatus))
if args['level'] == "detail":
    print ("<date>{}</date>".format(now))
print ("</{}>".format(args['level']))
print ("</host-status-information>")

Configuration

Enable Execution of Python Scripts

To enable the device to execute unsigned Python scripts:

  1. Configure the language python or language python3 statement, as appropriate for the Junos OS release.

    content_copy zoom_out_map
    [edit]
    user@host# set system scripts language (python | python3)
    Note:

    Starting in Junos OS Release 20.2R1 and Junos OS Evolved Release 22.3R1, the device uses Python 3 to execute YANG action and translation scripts. In earlier releases, Junos OS only uses Python 2.7 to execute these scripts, and Junos OS Evolved uses Python 2.7 by default to execute the scripts.

  2. Commit the configuration.

    content_copy zoom_out_map
    [edit]
    user@host# commit and-quit
    

Load the RPC on the Device

To add the RPC and action script to the Junos schema on the device:

  1. Download the YANG module and action script to the Junos device.

  2. Ensure that the Python action script meets the following requirements:

  3. (Optional) Validate the syntax for the YANG module and action script.

    content_copy zoom_out_map
    user@host> request system yang validate module /var/tmp/rpc-style-test.yang action-script /var/tmp/rpc-style-test.py
    YANG modules validation : START
    YANG modules validation : SUCCESS
    Scripts syntax validation : START
    Scripts syntax validation : SUCCESS
    
  4. Add the YANG module and action script to a new YANG package.

    content_copy zoom_out_map
    user@host> request system yang add package rpc-style-test module /var/tmp/rpc-style-test.yang action-script /var/tmp/rpc-style-test.py
    YANG modules validation : START
    YANG modules validation : SUCCESS
    Scripts syntax validation : START
    Scripts syntax validation : SUCCESS
    TLV generation: START
    TLV generation: SUCCESS
    Building schema and reloading /config/juniper.conf.gz ...
    Restarting mgd ...
    
  5. When the system prompts you to restart the Junos OS CLI, press Enter to accept the default value of yes, or type yes and press Enter.

    content_copy zoom_out_map
    WARNING: cli has been replaced by an updated version:
    ...
    Restart cli using the new version ? [yes,no] (yes) yes
    
    Restarting cli ...
    

Verify the RPC

Purpose

Verify that the RPC works as expected.

Action

From operational mode, execute the RPC in the CLI by issuing the command defined by the junos:command statement in the RPC definition. Include the hostip input argument, and include the level argument for each different level of output.

content_copy zoom_out_map
user@host> show host-status hostip 198.51.100.1 level brief
Brief output
198.51.100.1   Host is Active

You can view the corresponding XML by appending | display xml to the command.

content_copy zoom_out_map
user@host> show host-status hostip 198.51.100.1 level brief | display xml
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/18.3R1/junos">
    <host-status-information>
        <brief>
            <hostip>
                198.51.100.1
            </hostip>
            <status>
                Host is Active
            </status>
        </brief>
    </host-status-information>
    <cli>
        <banner></banner>
    </cli>
</rpc-reply>

Similarly, for the detailed output:

content_copy zoom_out_map
user@host> show host-status hostip 198.51.100.10 level detail
Detail output
198.51.100.10   Host is Inactive Fri Feb  8 11:55:54 PST 2019
content_copy zoom_out_map
user@host> show host-status hostip 198.51.100.10 level detail | display xml
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/18.3R1/junos">
    <host-status-information>
        <detail>
            <hostip>
                198.51.100.10
            </hostip>
            <status>
                Host is Inactive
            </status>
            <date>
                Fri Feb  8 16:03:35 PST 2019
            </date>
        </detail>
    </host-status-information>
    <cli>
        <banner></banner>
    </cli>
</rpc-reply>

Meaning

When you execute the RPC, the device invokes the action script. The action script prints the XML hierarchy for the given level of output as defined in the RPC output statement. When the RPC is executed in the CLI, the device uses the CLI formatting defined in the RPC to convert the XML output into the displayed CLI output.

Change History Table

Feature support is determined by the platform and release you are using. Use Feature Explorer to determine if a feature is supported on your platform.

Release
Description
21.2R1 and 21.2R1-EVO
Starting in Junos OS Release 21.2R1 and Junos OS Evolved Release 21.2R1, when the device passes command-line arguments to a Python action script, it prefixes a single hyphen (-) to single-character argument names and prefixes two hyphens (--) to multi-character argument names.
footer-navigation