Nokia — Proprietary and confidential.
Use pursuant to applicable agreements.
CLI PLUG-IN GUIDE
Release 20.6
Nokia is a registered trademark of Nokia Corporation. Other products and company
names mentioned herein may be trademarks or tradenames of their respective
owners.
The registered trademark Linux® is used pursuant to a sublicense from the Linux
Foundation, the exclusive licensee of Linus Torvalds, owner of the mark on a
worldwide basis.
The information presented is subject to change without notice. No responsibility is
assumed for inaccuracies contained herein.
Contains proprietary/trade secret information which is the property of Nokia and must
not be made available to, or copied or used by anyone outside Nokia without its
written authorization. Not to be used or disclosed except in accordance with
applicable agreements.
2
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
Table of contents
1Getting started ................................................................................5
1.1About this document....................................................................................5
1.2Summary of changes...................................................................................5
This chapter provides an overview of this document, includes summaries of changes
from previous releases, and lists precautionary messages and command
conventions.
The Nokia Service Router Linux (SR Linux) CLI is a python-based application that
can load dynamic plug-ins. Plug-ins are custom show commands that you can create
and run from the SR Linux CLI. This document describes how to create custom CLI
plug-ins, and defines the classes and utility functions used to create them. It also
defines how to install, modify, and remove a CLI plug-in.
This document is intended for network technicians, administrators, operators,
service providers, and others who need to create and install custom show
commands.
1.2Summary of changes
There are no changes since the last release.
1.3Precautionary messages
Observe all dangers, warnings, and cautions in this document to avoid injury or
equipment damage during installation and maintenance. Follow the safety
procedures and guidelines when working with and near electrical equipment.
Table 1 describes information symbols contained in this document.
Edition: 13HE 16119 AAAA TQZZA5
Getting started
Table 1Information symbols
SymbolMeaningDescription
DangerWarns that incorrect handling and installation could result in bodily injury.
An electric shock hazard could exist. Before beginning work on this
equipment, be aware of hazards involving electrical circuitry, be familiar
with networking environments, and implement accident prevention
procedures.
WarningWarns that incorrect handling and installation could result in equipment
damage or loss of data.
CautionWarns that incorrect handling may reduce component or system
performance.
NoteNotes contain suggestions or additional operational information.
CLI PLUG-IN GUIDE
Release 20.6
1.4Conventions
Nokia SR Linux documentation uses the following command conventions.
• Bold type indicates a command that the user must enter.
• Input and output examples are displayed in Courier text.
• An open right angle bracket indicates a progression of menu choices or simple
command sequence (often selected from a user interface). Example: start >
connect to
• Angle brackets (< >) indicate an item that is not used verbatim. For example, for
the command show ethernet <name>, name should be replaced with the name
of the interface.
• A vertical bar (|) indicates a mutually exclusive argument.
• Braces ({ }) indicate a required choice. When braces are contained within square
brackets, they indicate a required choice within an optional element.
• Italic type indicates a variable.
Generic IP addresses are used in examples. Replace these with the appropriate IP
addresses used in the system.
6
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
2Show routines
Show routines
This chapter provides a tutorial on how to create a routine, or set of instructions, that
results in a custom show command. It also provides a detailed description of all the
classes and utility functions used to create custom show commands.
Before creating a show routine, the following is recommended:
• Whenever you receive Data from the server, print it using:
print(str(data))
This makes it easier to visualize the data hierarchy.
• While building the SchemaNode and populating the Data structure, do not focus
on the layout of your show routine. Instead, use the output of the following:
show <your-routine> | as json
This JSON output contains all the information currently in your show routine, in
the correct hierarchy. Once the JSON output looks correct, then plan how to
format it.
2.1Create a show routine
To create a show routine, you perform the following high-level steps:
Step 1.Build a SchemaNode to describe the data’s data model the show routine
will construct.
Step 2.Retrieve the state from the management server using
state.server_data_store.get_data(<path>)
Step 3.Populate a Data object with all the data (keys/fields/…) of the show routine.
Step 4.Add Formatter instances to determine how the data will be formatted.
Step 5.Implement the callback method to pass the Data structure to the
output.print_data command.
Step 6.Use streaming to optimize reports when working with large amounts of
data.
Edition: 13HE 16119 AAAA TQZZA7
Show routines
CLI PLUG-IN GUIDE
Release 20.6
The following is an output example once all steps are completed. As you perform the
steps in this section, you will be able to see how this example is built.
======================================
name: interface-1
description: The first interface
admin-state: enable
Schema nodes describe a data model. Similar to the output of the tree command or
the content of a YANG file, they indicate what lists, containers, keys, fields, and leaflists can be created.
To build a SchemaNode, start with a FixedSchemaRoot()
then add your top-level list/container using FixedSchemaNode.add_child() as
shown in the SchemaNode reference.
The code above generates a data model for the following YANG model:
8
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
Show routines
list interface {
key "name";
leaf "description";
leaf "admin-state";
list child {
key "Child-Id";
leaf "Is-Cool";
}
}
Ensure that the filter auto-completes all fields by passing the schema node into the
add_command call when you install the plug-in. This ensures that the filter operator
(|) can auto-complete all fields. For example:
To format the output, assign Formatter instances to the different Data objects. The
type of Formatter determines whether the output is formatted using key: value pairs,
as a grid-based table, or using a custom format.
from srlinux.data import Border, ColumnFormatter, Data, TagValueFormatter, Borders,
Indent
server_data = self._fetch_state(state, arguments)
result = self._populate_data(server_data)
self._set_formatters(result)
output.print_data(result)
Once you have completed Steps 1 - 5 (in sections 2.1.1 - 2.1.5), the show routine
first shown in section 2.1Create a show routine is now complete.
The following is an example of the complete show routine code:
from srlinux import strings
from srlinux.data import Border, ColumnFormatter, TagValueFormatter, Borders, Data,
Indent
from srlinux.location import build_path
from srlinux.mgmt.cli import CliPlugin
from srlinux.schema import FixedSchemaRoot
from srlinux.syntax import Syntax
Indent(ColumnFormatter(ancestor_keys=False, borders=Borders.Header), ind
2.1.7Step 6: Use streaming to optimize reports
The previous steps detail how to obtain data, and then separately print a report. With
streaming, data is retrieved and begins printing immediately. This is useful for reports
that have large amounts of data (for example, route tables) because printing begins
immediately instead of waiting for the entire data collection to complete.
Perform the following to implement streaming:
1. Enter state.server_data_store.stream_data(<path>) instead of
state.server_data_store.get_data(<path>) to retrieve server data
2. When constructing data, flush the data using flush_fields() and flush_children().
If no data is flushed, it displays as though streaming was not implemented.
Implement flushing as soon as you know that a node is finished (but not sooner).
For example:
data.synchronizer.flush_fields(data)
for interface in server_data.interface.items():
data = data_root.interface.create(interface.name)
data.description = interface.description
data.admin_state = interface.admin_state
data.synchronizer.flush_fields(data)
Note that you cannot change fields after a flush_fields() is called, and you cannot
create new child nodes for the list you called flush_children().
3. Enter output.stream_data instead of output.print_data. Because it is a context
manager python class, it can be used as `with output.stream_data(result):`.
When the `with` block exits, flush_fields() and flush_children() are called on
every node to ensure everything prints at the end.
The following is an example of the complete show routine code using streaming.
from srlinux import strings
from srlinux.data import Border, ColumnFormatter, TagValueFormatter, Borders, Data,
Indent
from srlinux.location import build_path
from srlinux.mgmt.cli import CliPlugin
from srlinux.schema import FixedSchemaRoot
from srlinux.syntax import Syntax
This chapter contains procedures for installing, modifying, and removing a CLI plugin on the SR Linux.
To install a CLI plug-in, perform the following steps:
1. Open an SSH session.
2. Save the CLI plug-in Python code to a file; for example, my_cli.py.
3. Copy the CLI plug-in file to the /opt/srlinux/python/virtual-env/lib/python3.6/site-packages/srlinux/mgmt/cli/plugins/reports
directory.
4. Edit the file /opt/srlinux/python/virtual-env/lib/python3.6/site-packages/srlinux-0.1-py3.6.egg-info/entry_points.txt
and add an entry for the new CLI plug-in. For example:
The output can be customized using the following constructor arguments:
ancestor_keys : bool or list
• Controls whether the ancestor keys will be added as columns to the output table
• True - (the default) includes all ancestor keys
• False - does not include any ancestor keys
• A list provides more granular control. The list must contain a value for each
ancestor key, and can contain:
- None - suppresses the key
18
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
Classes and utility functions
- A string to specify the column key to use for the ancestor key
For example, when passed [None, “A”, None], the first and third ancestor key are
dropped, and the second is renamed to “A”.
horizontal_alignment : dict{str: Alignment}
Dictionary mapping column-names to their horizontal alignment (Alignment.Left/
Center/Right). Columns not mentioned are left-aligned.
vertical_alignment : dict{str: Alignment}
Dictionary mapping column-names to their vertical alignment (Alignment.Top/Middle/
Bottom). Columns not mentioned are top-aligned.
borders : Borders
Combination of Borders values indicating which borders to print. Defaults to
“Borders.Outside | Borders.Header | Borders.Columns”.
Class srlinux.data.Alignment
The values used to align data in the table cells. Table 3 lists the alignment values.
Table 3Cell alignment values
Alignment valueDescription
Left= 1Horizontally aligns the data to the left
Right= 2Horizontally aligns the data to the right
Center= 3Horizontally centers the data
Top= 4Vertically aligns the data to the top
Middle= 5Vertically centers the data
Bottom= 6Vertically aligns the data to the bottom
Class srlinux.data.Borders
Specifies which borders to draw when drawing the table. Values can be combined
together using the symbol ‘|’. For example: Borders.Outside | Borders.Header
draws a border around the table and line below the header. Table 4 defines the
border values to use when drawing a table.
Edition: 13HE 16119 AAAA TQZZA19
Classes and utility functions
Table 4Types of table borders
Table border Description
Nothing= 0Draws no borders
Outside= 1Draws a border around the table
Header= 2Draws a horizontal line between the header and the first row
Rows= 4Draws a horizontal line between the rows
Columns= 8Draws a vertical line between the columns
4.1.2TagValueFormatter
Class srlinux.data.TagValueFormatter(filter=None)
CLI PLUG-IN GUIDE
Release 20.6
Formats the specified Data object as a list of “tag: value” pairs (one on each line).
Example output:
key : <name>
field: <value>
4.1.3TagValueWithKeyLineFormatter
Class srlinux.data.TagValueWithKeyLineFormatter(filter=None)
Formats the specified Data object as a single line with the name and the keys,
followed by a list of “tag: value” pairs (one on each line).
Example output:
node <name> id <id>
field: <value>
20
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
4.1.4Indent
Classes and utility functions
Class srlinux.data.Indent(formatter, indentation=' ')
Decorator that indents every line printed by the wrapped formatter.
A common use case for this decorator is to enhance the format of some fields, but
keeps the original field values available for when the output is formatted as JSON.
In this case, add both the original fields and the combined field to the Data object,
and filter the original fields out for formatting.
data = Data(schema)
# The 2 original fields. Added to data so that 'show <snip> | as json' displays them
filter : FilterFilters out fields/leaf-lists from the output. Fields that do not
match the filter are not printed.
4.2.4print_line
srlinux.data.print_line(width, character='-')
Returns a line of length “width”, consisting of the specified character.
4.2.5print_double_line
srlinux.data.print_double_line(width)
Returns a line of length “width” consisting of ============.
28
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
4.2.6indent
4.2.7format_value
Classes and utility functions
srlinux.data.indent(values, indentation)
Indents each given value with the specified indentation. The indentation can either
be a string, or an integer indicating the number of spaces to use for the indentation.
srlinux.data.format_value(value)
Formats the Data value as a string, which works for key, field, and leaf-list values of
all accepted types (number, string, bool), even if the field/leaf-list is absent.
4.3Data
The class used to represent all data; both the data retrieved from the server and the
data displayed in the show report.
Class srlinux.data.data.Data(schema, parent=None, **keys)
Allows easy access to a configuration/state instance. When creating a top-level Data
object, you must specify an instance of a SchemaNode. The code analyzes the
schema, and makes all fields, keys, leaf-lists, and children accessible as attributes.
For example, assume that this is the data model:
list interface {
key 'name';
field 'admin-state';
leaflist 'values';
list subinterface {
key 'id';
}
}
You can then:
• Get the keys:
value = data.name
Edition: 13HE 16119 AAAA TQZZA29
Classes and utility functions
• Get and set the fields:
value = data.admin_state # returns the value or None if unset
data.admin_state = 'enabled'
• Get and set leaflists:
value = data.values # returns a list
data.values = ['a', 'b']
• Access children:
child = data.subinterface.create(42) # Creates the subinterface with id '42'
child = data.subinterface.get(42)
if data.subinterface.exists(42):
for si in data.subinterface.items():
Note: Names are changed so that any character that is not a to z, A to Z, or 0 to 9 is replaced
by an “_”.
CLI PLUG-IN GUIDE
Release 20.6
# Returns True/False
# Walks all subinterfaces, ordered by their key
Children
When accessing a child (data.subinterface in the preceding example), an instance of
DataChildrenOfType is returned. Follow the link to see all the accessors it provides.
Values
All key/field/leaf-list values are of the following types:
•bool
• integer
• string
Formatters
To generate the show report, Formatter objects are used. These can be tied to a
specific Data object using two methods:
• By assigning a formatter to the Data.formatter property.
• By using Data.set_formatter().
30
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
Classes and utility functions
Both methods assign the formatter to all sibling Data objects. For example, calling
the following sets the formatter for all interfaces and not just for subinterface 42.
get(name)Returns the value of the specified key, field, leaf-list,
get_annotations(name=None)Returns a list containing the annotations of this node
add_annotation(annotation, name=None)
formatterReturns the Formatter that can be used to generate
iter_format(max_width)Invokes the Formatter of this Data object. Returns
iter_format_children(max_width)Invokes the Formatter of all children of this Data
Iterates over all DataChildrenOfType instances for
which the predicate is True. By default, this returns
all children.
or child.
(if called with no arguments) or the field with the
specified name.
Adds the specified annotation to this node (when
called with a single argument) or to the field with the
specified name (when called with two arguments).
The annotation must be an instance of Annotation.
the show report for this Data object.
an iterator over the formatted output lines.
object. Returns an iterator over the formatted output
lines.
32
set_formatter(schema, formatter)Adds a Formatter to the Data object with the
specified schema. The schema can be specified as
an XPath string (without keys). For example, “/
interface/subinterface”.
get_schema(path)Get the SchemaNode of the Data object with the
specified path. The path must be an XPath string, for
example, “/interface/subinterface”.
3HE 16119 AAAA TQZZAEdition: 1
CLI PLUG-IN GUIDE
Release 20.6
4.4DataChildrenOfType
Classes and utility functions
Use this class when you need to access children through a Data object. It allows you
to retrieve, create, and iterate all children.
Class srlinux.data.data.DataChildrenOfType(schema, parent)
The children of a Data object of a single type.
Returned by Data.get_children() or by accessing the attribute with the child name
(for example, Data.interface). Most methods require you to pass a value for each key
defined in the schema.