ON THIS PAGE
Using Salt to Configure Devices Running Junos OS
Juniper Networks provides support for using Salt to manage devices running Junos OS, and the Junos execution and state modules (for Salt) define functions that enable you to manage the Junos OS configuration. This topic discusses how to use Salt to generate, provision, and manage Junos OS configurations.
Overview of Using Salt to Provision Junos OS Configurations
The Junos execution and state modules (for Salt) enable you to use Salt to manage the configuration of a device running Junos OS. The modules define functions to perform the following tasks:
Lock and unlock the configuration database
Load configuration data
Commit the configuration
Roll back the configuration
Configure the device hostname and commit the change
Table 1 lists the functions you can use to manage the configuration and provides a brief description of each function. You can use the execution functions to perform the operations on the Salt master command line. But more often, you will define the state in which the managed device must be and use the state functions to apply the configuration.
Junos Execution Function |
Junos State Function |
Description |
---|---|---|
Commit the changes loaded into the target configuration database. |
||
Perform a |
||
Lock, modify, commit, and unlock the target configuration database. |
||
Load the configuration data in the specified file into the target configuration database. |
||
Request an exclusive lock on the candidate configuration. |
||
Roll back the configuration to a previously committed configuration and commit it. |
||
Configure the hostname of a managed device running Junos OS and commit the change. |
||
Release the exclusive lock on the candidate configuration. |
The basic process for making configuration changes is to lock
the configuration database, load the configuration changes, commit
the configuration to make it active, and then unlock the configuration
database. You can use the corresponding function to execute each operation
individually, or you can use the junos.install_config
function to execute all of the operations with a single function
call.
By default, the junos.install_config
function makes changes to the candidate configuration database using configure exclusive
mode, which automatically locks and unlocks
the configuration database. The function compares the loaded configuration
with the current configuration and only applies the new configuration
if there are changes. If the function modifies the configuration,
it then performs a commit check
and commit
operation.
We recommend using the junos.install_config
function to make configuration changes, because it handles the entire
configuration workflow. The function also enables you to save the
configuration differences to a file and use different configuration
modes. For example, you can use configure private
mode to modify a private copy of the candidate configuration, as
described in How to Specify the Configuration Mode.
When loading new configuration data with the junos.load
or junos.install_config
function, you can specify the load operation, and the source and
format of the changes.
Load operation—The load operation determines how the configuration data is loaded into the candidate configuration. The functions support many of the same load operations that are available in the Junos OS CLI, including merge, override, replace, and update. For more information, see How to Specify the Load Operation.
Format—You can configure devices running Junos OS using one of the standard, supported formats. You can provide configuration data or Jinja2 templates as text, Junos XML elements, Junos OS
set
commands, or JSON. For more information, see How to Specify the Format of the Configuration Data to Load.Configuration data source—You can load configuration data from a file containing a partial or complete configuration or a Jinja2 template. For details, see How to Load Configuration Data and How to Load Configuration Data Using a Jinja2 Template.
After modifying the configuration, you must commit the configuration
to make it the active configuration on the device. The junos.install_config
, junos.rollback
, and junos.set_hostname
functions automatically
commit the changes to the configuration. You can also execute the junos.commit
function to perform a commit operation.
For information about the behavior of the different functions and
their supported commit options, see How to Commit the Configuration.
In addition to loading new configuration data, you can use the junos.rollback
function to roll back the configuration
to a previously committed configuration. The function automatically
commits the updated configuration. For more information, see How to Roll Back the Configuration.
How to Lock and Unlock the Configuration Database
You can lock the candidate configuration before modifying it
to prevent other users or applications from updating it until the
lock is released. This is equivalent to the configure exclusive
command in the CLI. We recommend locking the configuration before
making changes, particularly on devices where multiple users are authorized
to change the configuration, because a commit operation applies to
all changes in the candidate configuration, not just those made by
the user or application that requests the commit.
The junos.install_config
function
makes changes to the candidate configuration database using configure
exclusive
mode, which automatically locks the configuration
database, loads and commits the changes, and unlocks the database.
However if you need to execute the load and commit operations separately,
for example, by using the junos.load
and junos.commit
functions, you can explicitly lock and
unlock the database by using the junos.lock
and junos.unlock
execution or state functions.
To explicitly lock the configuration database before modifying
it, use the junos.lock
function. For example:
saltuser@salt-master:~$ sudo salt 'router1' junos.lock router1: ---------- message: Successfully locked the configuration. out: True
To unlock the database and discard any uncommitted changes,
use the junos.unlock
function. For example:
saltuser@salt-master:~$ sudo salt 'router1' junos.unlock router1: ---------- message: Successfully unlocked the configuration. out: True
If the configuration database has been modified, or if another
user already has an exclusive lock on it, the junos.lock
function returns a LockError
message,
as shown in the following examples:
saltuser@salt-master:~$ sudo salt 'router1' junos.lock router1: ---------- message: Could not gain lock due to : "LockError(severity: error, bad_element: None, message: configuration database modified)" out: False
saltuser@salt-master:~$ sudo salt 'router1' junos.lock router1: ---------- message: Could not gain lock due to : "LockError(severity: error, bad_element: None, message: configuration database locked by: admin terminal p1 (pid 28508) on since 2019-08-12 12:46:52 PDT exclusive [edit])" out: False
How to Specify the Configuration Mode
The junos.install_config
function
enables you to make changes in different configuration modes. By default,
the function makes changes to the candidate configuration database
using configure exclusive
mode. The configure exclusive
mode locks the candidate global configuration (also known as the shared configuration database) for as long as the function
requires to make the requested changes to the configuration. Locking
the database prevents other users from modifying or committing changes
to the database until the lock is released.
To specify a different mode, set the mode
parameter equal to the desired mode. Supported modes include batch
, dynamic
, ephemeral
, exclusive
, and private
. For information about the different modes,
see the CLI User Guide.
For example, the following command makes changes to the configuration
using configure private
mode, which opens a private copy
of the candidate configuration:
saltuser@salt-master:~$ sudo salt 'router1' junos.install_config 'salt://configs/mpls-config.set' mode=private router1: ---------- message: Successfully loaded and committed! out: True
Similarly, you can include the argument in a Salt state file.
saltuser@salt-master:~$ cat /srv/salt/junos_mpls_config.sls Install MPLS Config: junos.install_config: - name: salt://configs/mpls-config.set - mode: private
You can also use the junos.install_config
function to update the ephemeral configuration database on devices
that support this database. The ephemeral database is an alternate
configuration database that provides a fast programmatic interface
for performing configuration updates on devices running Junos OS.
You must have Salt version 3001 and Junos PyEZ Release 2.1.3 or later
to use this feature
The ephemeral configuration database is an advanced feature, which if used incorrectly can have a serious negative impact on the operation of the device. For more information, see Understanding the Ephemeral Configuration Database.
To configure the default instance of the ephemeral configuration
database, set the mode
argument equal to ephemeral
. For example:
saltuser@salt-master:~$ cat /srv/salt/junos_ephemeral_config.sls Install MPLS config in default ephemeral instance: junos.install_config: - name: salt://configs/mpls-ephemeral-config.set - mode: ephemeral
To configure a user-defined instance of the ephemeral configuration
database, set the mode
argument equal to ephemeral
, and set the ephemeral_instance
argument equal to the name of the instance.
saltuser@salt-master:~$ cat /srv/salt/junos_ephemeral_instance_config.sls Install MPLS config in ephemeral instance: junos.install_config: - name: salt://configs/mpls-ephemeral-instance-config.set - mode: ephemeral - ephemeral_instance: eph1
How to Specify the Load Operation
You can use the junos.load
and junos.install_config
functions to load configuration
changes using a load merge
, load replace
, load override
, or load update
operation. You specify
the desired load operation by including or omitting the appropriate
arguments for that function. If you do not specify a load operation,
the default is load replace
. Table 2 summarizes the
arguments required for each type of load operation.
Load Operation |
Function Argument |
Description |
---|---|---|
|
|
Merge the loaded configuration with the existing configuration. |
|
|
Replace the entire configuration with the loaded configuration. |
|
– |
Merge the loaded configuration with the existing configuration,
but replace statements in the existing configuration with those that
specify the |
|
|
Compare the complete loaded configuration against the existing configuration. Each configuration element that is different in the loaded configuration replaces its corresponding element in the existing configuration. During the commit operation, only system processes that are affected by changed configuration elements parse the new configuration. |
The following command replaces the entire configuration on the target device with the specified configuration and commits it. The RPC timeout is increased to provide sufficient time to load and commit the complete configuration.
saltuser@salt-master:~$ sudo salt 'router1' junos.install_config overwrite=True 'salt://configs/junos-complete-config.conf' dev_timeout=60
The equivalent state file is:
Replace complete configuration: junos.install_config: - name: salt://configs/junos-complete-config.conf - overwrite: True - dev_timeout: 60
How to Specify the Format of the Configuration Data to Load
The junos.load
and junos.install_config
functions enable you to configure devices running Junos OS using
one of the standard, supported formats. You can load configuration
data from a file containing a partial or complete configuration or
a Jinja2 template. The data can be provided as text, Junos XML elements,
Junos OS set
commands, or JSON.
You must specify the format of the configuration data either
by adding the appropriate extension to the configuration file or by
explicitly including the format
argument
in the function call. Table 3 summarizes the supported formats for the configuration data
and the corresponding value for the file extension and format
parameter. If you include the format
argument, it overrides the format indicated
by the file extension.
Configuration Data Format |
File Extension |
format Parameter |
---|---|---|
CLI configuration statements (text) |
.conf |
|
JavaScript Object Notation (JSON) |
.json |
|
Junos OS |
.set |
|
Junos XML elements |
.xml |
|
Devices running Junos OS support loading configuration data in JSON format starting in Junos OS Release 16.1R1.
How to Load Configuration Data
The junos.load
and junos.install_config
functions enable you to load configuration data from a file that
contains a partial or complete configuration or a Jinja2 template.
The file can reside on the Salt master or the proxy minion server.
The functions must use the salt:// notation to specify a path on the Salt master, and they must use
an absolute path to specify a path on the proxy minion server. If
the file does not use one of the accepted file extensions to indicate
the format of the configuration data, then the function call must
also include the format
argument to specify
the format of the data.
Table 4 describes
the configuration data sources that you can use and lists the execution
and state function arguments required to specify the location of the
file. The execution functions can specify the path as a positional
argument or by using the path
keyword.
Configuration Data Source |
Description |
Location |
Execution Function Argument |
State Function Argument |
---|---|---|---|---|
Configuration data file |
File containing configuration data formatted as ASCII
text, Junos XML elements, Junos OS |
Salt master—use salt:// notation Proxy minion server—use an absolute path |
|
|
Jinja2 template file |
File containing a Jinja2 template formatted as ASCII
text, Junos XML elements, Junos OS Include the |
Salt master—use salt:// notation Proxy minion server—use an absolute path |
|
|
For example, the following file contains Junos OS set
commands that configure two op scripts. The file’s extension
indicates the format for the configuration data.
saltuser@salt-master:~$ cat /srv/salt/configs/op-scripts.set set system scripts op file bgp.slax set system scripts op file ospf.slax
The following Salt command uses the junos.install_config
execution function to load and commit the configuration on the target
device. The path is provided as a positional argument.
saltuser@salt-master:~$ sudo salt 'router1' junos.install_config 'salt://configs/op-scripts.set' router1: ---------- message: Successfully loaded and committed! out: True
The equivalent state file is:
saltuser@salt-master:~$ cat /srv/salt/junos-config-op-scripts.sls Installing op scripts: junos.install_config: - name: salt://configs/op-scripts.set - comment: committed using Salt
saltuser@salt-master:~$ sudo salt 'router1' state.apply junos-config-op-scripts router1: ---------- ID: Installing op scripts Function: junos.install_config Name: salt://configs/op-scripts.set Result: True Comment: Started: 04:19:59.819155 Duration: 14853.384 ms Changes: ---------- message: Successfully loaded and committed! out: True Summary for router1 ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 14.853 s
The junos.install_config
function
automatically performs a diff between the candidate configuration
and the requested configuration. The function only applies the configuration
if there are changes. If you attempt to apply the same configuration
a second time, the junos.install_config
function returns a message that the configuration has already been
applied and does not load and commit it again, as shown in the following
example:
saltuser@salt-master:~$ sudo salt 'router1' state.apply junos-config-op-scripts router1: ---------- ID: Installing op scripts Function: junos.install_config Name: salt://configs/op-scripts.set Result: True Comment: Started: 06:01:52.365353 Duration: 778.843 ms Changes: ---------- message: Configuration already applied! out: True Summary for router1 ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 778.843 ms
How to Load Configuration Data Using a Jinja2 Template
The junos.load
and junos.install_config
execution and state functions support using Jinja2 templates for
Junos OS configuration data. Jinja is a template engine for Python
that enables you to generate documents from predefined templates.
The templates, which are text files in the desired language, provide
flexibility through the use of expressions and variables. You can
create Junos OS configuration data using Jinja2 templates in one of
the supported configuration formats, which includes ASCII text, Junos
XML elements, Junos OS set
commands, and JSON. The functions
use the Jinja2 template and a supplied dictionary of variables to
render the configuration data.
Jinja2 templates provide a powerful method to generate configuration
data, particularly for similar configuration stanzas. For example,
rather than manually adding the same configuration statements for
each interface on a device, you can create a template that iterates
over a list of interfaces and creates the required configuration statements
for each one. In Jinja, blocks are delimited by '{%
' and '%}
' and variables are
enclosed within '{{
' and '}}
'.
To load a Jinja2 template, you must include the following
parameters in the junos.load
or junos.install_config
function call:
Template path—Specify the path to a template file on the Salt master or proxy minion server, as described in How to Load Configuration Data.
Template format—Set the
format
argument to indicate the format of the configuration data if the template file does not use one of the accepted file extensions to specify the format. For information about specifying the format, see How to Specify the Format of the Configuration Data to Load.Template variables—The template can reference Salt internal variables like those defined in pillar or grain data. Any variables that are not already defined within the Salt system must be supplied in the
template_vars
argument. Thetemplate_vars
value is a dictionary of keys and values that are required to render the Jinja2 template.Note:If your template only includes Salt internal variables like pillar data, grain data, and functions, the
junos.install_config
function might need to definetemplate_vars: True
in order to render the template.
The following sample Jinja2 template generates configuration data that enables MPLS on logical unit 0 for each interface in a given list and also configures the interface under the MPLS and RSVP protocols.
saltuser@salt-master:~$ cat /srv/salt/configs/junos-config-mpls-jinja2-template.conf interfaces { {% for item in template_vars['interfaces'] %} {{ item }} { description "{{ template_vars['description'] }}"; unit 0 { family {{ template_vars['family'] }}; } } {% endfor %} } protocols { mpls { {% for item in template_vars['interfaces'] %} interface {{ item }}; {% endfor %} } rsvp { {% for item in template_vars['interfaces'] %} interface {{ item }}; {% endfor %} } }
The following command uses the Jinja2 template and the variables
defined in template_vars
to render the
configuration data, which is then loaded and committed on the target
host:
saltuser@salt-master:~$ sudo salt 'router1' junos.install_config 'salt://configs/junos-config-mpls-jinja2-template.conf' template_vars='{ "interfaces" : ["ge-1/0/1", "ge-1/0/2", "ge-1/0/3"], "description" : "MPLS interface", "family" : "mpls" }' router1: ---------- message: Successfully loaded and committed! out: True
The following state file loads the same configuration. The configuration
differences are stored in the diffs_file
file on the proxy minion server.
saltuser@salt-master:~$ cat /srv/salt/junos_install_config_mpls.sls Install Junos OS config: junos.install_config: - name: 'salt://configs/junos-config-mpls-jinja2-template.conf' - comment: committed using Salt - diffs_file: /home/saltuser/junos-config-mpls-diff - template_vars: interfaces: ['ge-1/0/1', 'ge-1/0/2', 'ge-1/0/3'] description: MPLS interface family: mpls
When you apply the state, Salt renders the configuration and loads and commits the configuration on the device.
saltuser@salt-master:~$ sudo salt 'router1' state.apply junos_install_config_mpls router1: ---------- ID: Install Junos OS config Function: junos.install_config Name: salt://configs/junos-config-mpls-jinja2-template.conf Result: True Comment: Started: 05:28:51.575045 Duration: 23675.957 ms Changes: ---------- message: Successfully loaded and committed! out: True Summary for router1 ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 23.676 s
The function generates the following configuration data, which is loaded into the candidate configuration on the device and committed:
interfaces { ge-1/0/1 { description "MPLS interface"; unit 0 { family mpls; } } ge-1/0/2 { description "MPLS interface"; unit 0 { family mpls; } } ge-1/0/3 { description "MPLS interface"; unit 0 { family mpls; } } } protocols { mpls { interface ge-1/0/1.0; interface ge-1/0/2.0; interface ge-1/0/3.0; } rsvp { interface ge-1/0/1.0; interface ge-1/0/2.0; interface ge-1/0/3.0; } }
How to Commit the Configuration
After modifying the configuration, you must commit the configuration
to make it the active configuration on the device. The junos.install_config
, junos.rollback
, and junos.set_hostname
functions load
the requested configuration changes and then automatically perform
a commit check and commit operation. You can also use the individual junos.commit_check
and junos.commit
functions to perform a commit check and commit operation, for example,
after using the junos.load
function to
update the configuration.
The Junos OS CLI provides options for the commit operation, such as adding a commit comment or synchronizing the configuration on multiple Routing Engines. Some of these options are supported by the Junos execution and state module functions. Table 5 outlines the commit options that are available and the functions that support them. Supported arguments are valid for both the execution function and the state function.
Function Argument |
Description |
Functions That Support the Argument |
CLI Command Equivalent |
---|---|---|---|
|
Log a comment for that commit operation in the system log file and in the device’s commit history. |
|
|
|
Require that a commit operation be confirmed within a specified amount of time after the initial commit. Otherwise, roll back to the previously committed configuration. Set the argument to |
|
|
|
Return detailed information about the commit process. |
|
|
|
Wait for completion of the operation using the specified value as the timeout. |
|
– |
|
Synchronize and commit the configuration on both Routing Engines, even if there are open configuration sessions or uncommitted configuration changes on the other Routing Engine. |
|
|
|
Synchronize and commit the configuration on both Routing Engines. |
|
|
Commit Comment
When you commit the configuration, you can include a brief comment
to describe the purpose of the committed changes. To log a comment
describing the changes, include the comment
argument and a message string. For example:
saltuser@salt-master:~$ sudo salt 'router1' junos.commit comment='Committed using Salt'
Similarly, in a state file:
saltuser@salt-master:~$ cat /srv/salt/junos_install_mx_config.sls Install Junos OS config: junos.install_config: - name: salt://configs/mx-config-common.set - comment: Committed using Salt
The commit comment is included in the system log message for the commit as well as logged in the commit history.
saltuser@salt-master:~$ sudo salt 'router1' junos.cli 'show system commit' router1: ---------- message: 0 2019-08-05 15:08:01 PDT by saltuser via netconf Committed using Salt ... out: True
Commit Confirmed
When you commit the candidate configuration, you can require an explicit confirmation for the commit to become permanent. If the commit is not confirmed within the specified amount of time, the device automatically loads and commits (rolls back to) the previously committed configuration. The confirmed commit operation is useful for verifying that a configuration change works correctly and does not prevent management access to the device. If the change prevents access or causes other errors, the automatic rollback to the previous configuration restores access to the device after the rollback deadline passes.
To require that a commit operation be confirmed within a specified
amount of time after the initial commit, include the confirm=minutes
argument. The
allowed range is 1 through 65,535 minutes. You can also specify confirm=True
to use the default time of 10 minutes.
The following command requires that the commit be confirmed within 15 minutes:
saltuser@salt-master:~$ sudo salt 'router1' junos.install_config 'salt://configs/mx-config-common.set' confirm=15 router1: ---------- message: Successfully loaded and committed! out: True
To confirm the commit operation, call either the junos.commit
or junos.commit_check
function.
saltuser@salt-master:~$ sudo salt 'router1' junos.commit comment='Confirming commit using Salt' router1: ---------- message: Commit Successful. out: True
Commit Detail
When you use the junos.commit
function
to commit the configuration, you can review the details of the entire
commit operation by including the detail=True
argument. When you include this argument, the function returns detailed
information about the commit process.
saltuser@salt-master:~$ sudo salt 'router1' junos.commit detail=True router1: ---------- message: ---------- routing-engine: ---------- name: re0 progress-indicator: |_ ---------- message: Obtaining lock for commit timestamp: 2019-08-14 11:17:50 PDT |_ ---------- message: updating commit revision timestamp: 2019-08-14 11:17:50 PDT ...
Commit Synchronize
When you use the junos.commit
function
to commit the configuration, you can synchronize and commit the configuration
on both Routing Engines in a dual Routing Engine system by including
the sync=True
argument. For example:
saltuser@salt-master:~$ sudo salt 'router1' junos.commit sync=True
When you include the sync=True
argument,
the device copies the candidate configuration stored on the local
Routing Engine to the other Routing Engine, verifies the candidate’s
syntactic correctness, and commits it on both Routing Engines. To
force the commit synchronize
operation to succeed even
if there are open configuration sessions or uncommitted configuration
changes on the other Routing Engine, use the force_sync=True
argument. Including this argument causes the device to terminate
any configuration sessions on the other Routing Engine before synchronizing
and committing the configuration.
Commit Timeout
The default time for an RPC to time out is 30 seconds. Large
configuration changes might exceed this value causing the operation
to time out before the configuration can be uploaded and committed.
To accommodate configuration changes that might require a commit time
that is longer than the default timeout interval, include the dev_timeout=seconds
argument,
and set the timeout interval to an appropriate value. For example:
saltuser@salt-master:~$ sudo salt 'router1' junos.install_config 'salt://configs/junos_mx_config.conf' dev_timeout=60
saltuser@salt-master:~$ cat /srv/salt/junos_install_mx_config.sls Install Config: junos.install_config: - name: salt://configs/junos_mx_config.conf - dev_timeout: 60
How to Roll Back the Configuration
Devices running Junos OS store a copy of the most recently committed configuration and up to 49 previous configurations, depending on the platform. You can roll back to any of the stored configurations. This is useful when configuration changes cause undesirable results, and you want to revert back to a known working configuration. Rolling back the configuration is similar to the process for making configuration changes on the device, but instead of loading configuration data, you perform a rollback, which replaces the entire candidate configuration with a previously committed configuration.
The salt.modules.junos.rollback
execution function
and the salt.states.junos.rollback
state function enable
you to roll back the configuration to a previously committed configuration
on a device running Junos OS. To roll back the configuration and commit
it, execute the function, and set the id
argument to the ID of the desired rollback configuration. Valid
ID values are 0 (zero) for the most recently committed configuration
through one less than the number of stored previous configurations
(maximum is 49). If you omit the id
keyword,
it defaults to 0.
For example, the following command rolls the configuration back to the previously committed configuration and commits it:
saltuser@salt-master:~$ sudo salt 'router1' junos.rollback id=1 comment='Rolling back configuration using Salt' router1: ---------- message: Rollback successful out: True
To roll back the configuration and log the configuration differences
in a file for later reference, include the diffs_file
argument, and set it to the path of the file on the proxy minion
server to which the differences are written.
saltuser@salt-master:~$ sudo salt 'router1' junos.rollback id=1 comment='Rolling back configuration using Salt' diffs_file='/home/saltuser/router1-rollback-diff' router1: ---------- message: Rollback successful out: True
The differences are saved to the specified file on the proxy minion server.
saltuser@minion:~$ cat /home/saltuser/router1-rollback-diff [edit system scripts op] - file bgp-neighbors.slax;