ON THIS PAGE
Use Ansible to Configure Junos Devices
SUMMARY Use the Juniper Networks Ansible modules to manage the configuration on Junos devices.
Juniper Networks provides an Ansible module that enables you to configure Junos devices. Table 1 outlines the available module. The user account that is used to make configuration changes must have permissions to change the relevant portions of the configuration on each device.
Content Set |
Module Name |
---|---|
|
The following sections discuss how to use the module to modify and commit the configuration on Junos devices.
Module Overview
The juniper.device.config
module enables you to perform the
following operations on Junos devices:
-
Load configuration data
-
Commit the configuration
-
Roll back the configuration
-
Load the rescue configuration
To modify the configuration, the module’s argument list must include either the
load
parameter to load new configuration data or the
rollback
parameter to revert to the rescue configuration or
a previously committed configuration. The basic process for making configuration
changes is to lock the configuration, load the configuration changes, commit the
configuration to make it active, and then unlock the configuration.
By default, the config
module makes changes to the candidate
configuration database using configure exclusive
mode, which
automatically locks and unlocks the candidate global configuration. You can also
specify a different configuration mode. For example, you can make changes to a
private copy of the candidate configuration or to the ephemeral configuration
database. For more information about specifying the configuration mode, see
How to Specify the Configuration Mode.
When loading new configuration data, in addition to specifying the configuration mode, you can also 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 selected configuration database. The function supports many of the same load operations that are available in the Junos OS CLI. For more information, see How to Specify the Load Action.
-
Format—You can configure Junos devices 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 information about specifying the format of the configuration data, see How to Specify the Format of the Configuration Data to Load. -
Configuration data source—You can load configuration data from a list of strings, a file on the local Ansible control node, a Jinja2 template, or a URL reachable from the client device by including the
lines
,src
,template
, orurl
parameter, respectively. For more information about specifying the source of the configuration data, see the following sections:
The config
module also enables you to load and commit the rescue
configuration or roll the configuration back to a previously committed
configuration. To load the rescue configuration or a previously committed
configuration, you must include the rollback
module argument.
For more information, see the following sections:
After modifying the configuration, you must commit the configuration to make it
the active configuration on the device. By default, the config
module commits the changes to the configuration. To alter this behavior or
supply additional commit options, see How to Commit the Configuration.
By default, when the config
module includes the
load
or rollback
arguments to change the
configuration, the module automatically returns the configuration changes in
diff or patch format in the module’s response. The differences are
returned in the diff
and diff_lines
variables.
To prevent the module from calculating and returning the differences, set the
diff
module argument to false
.
How to Specify the Configuration Mode
You can specify the configuration mode to use when modifying the device
configuration. To specify the configuration mode in your task, include the
config
module’s config_mode
parameter.
Supported configuration modes include:
-
batch
-
dynamic
-
ephemeral
-
exclusive
-
private
By default, the juniper.device.config
module makes changes to
the candidate configuration database using configure exclusive
mode. Configure exclusive mode locks the candidate global configuration (also
known as the shared configuration database) for as long as the module
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.
The following examples show how to configure a private copy of the candidate configuration and how to configure the ephemeral database.
Example: config_mode: "private"
The following playbook uses private
configuration mode to
modify a private copy of the candidate configuration:
--- - name: "Configure Device" hosts: dc1 connection: local gather_facts: no tasks: - name: "Configure op script" juniper.device.config: config_mode: "private" load: "set" lines: - "set system scripts op file bgp.slax" register: response - name: "Print the config changes" ansible.builtin.debug: var: response.diff_lines
user@ansible-cn:~/ansible$ ansible-playbook configure-script.yaml PLAY [Configure Device] ******************************************************* TASK [Configure op script] **************************************************** changed: [dc1a.example.net] TASK [Print the config changes] *********************************************** ok: [dc1a.example.net] => { "response.diff_lines": [ "", "[edit system scripts op]", "+ file bgp.slax;" ] } PLAY RECAP ******************************************************************** dc1a.example.net : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Configure the Ephemeral Database
You can use the juniper.device.config
module 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 Junos devices.
To open and configure the default instance of the ephemeral configuration
database, include the config_mode: "ephemeral"
argument.
For example:
--- - name: "Configure ephemeral database" hosts: dc1a connection: local gather_facts: no tasks: - name: "Configure the default ephemeral database" juniper.device.config: config_mode: "ephemeral" load: "set" lines: - "set protocols mpls label-switched-path to-hastings to 192.0.2.1"
To open and configure an existing user-defined instance of the ephemeral
configuration database, include the config_mode:
"ephemeral"
argument, and set the
ephemeral_instance
argument to the name of the
instance.
tasks: - name: "Configure a user-defined ephemeral instance" juniper.device.config: config_mode: "ephemeral" ephemeral_instance: "eph1" load: "set" lines: - "set protocols mpls label-switched-path to-hastings to 192.0.2.2"
How to Specify the Load Action
The juniper.device.config
module supports loading configuration
changes using many of the same load operations supported in the Junos OS CLI.
You specify the load operation by including the load
parameter
in the module’s argument list and setting it to the value of the corresponding
load operation. Table 2 summarizes the parameter settings required for each type of load
operation.
Load Operation |
load Argument |
Description |
---|---|---|
|
|
Merge the loaded configuration with the existing configuration. |
|
|
Replace the entire configuration with the loaded configuration. |
|
|
Load configuration data from a patch file. |
|
|
Merge the loaded configuration with the existing
configuration, but replace statements in the existing
configuration with those that specify the
|
|
|
Load configuration data that is in |
|
|
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. |
How to Specify the Format of the Configuration Data to Load
The juniper.device.config
module enables you to configure Junos
devices using one of the standard, supported formats. You can provide
configuration data as strings or files. Files can contain either configuration
data or Jinja2 templates. When providing configuration data within a string,
file, or Jinja2 template, supported formats for the data include text, Junos XML
elements, Junos OS set
commands, and JSON.
The config
module attempts to auto-detect the format of
configuration data that you supply as strings within the lines
argument. However, you can explicitly specify the format for strings by
including the format
argument. When you provide configuration
data in a file or Jinja2 template, you must specify the format of the data
either by adding the appropriate extension to the file or by including the
format
argument.
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
both the auto-detect format for strings and the format indicated by a 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 |
" |
When you set the module’s load
argument to
'override'
or 'update'
, you cannot use
the Junos OS set
command format.
How to Load Configuration Data as Strings
The juniper.device.config
module enables you to load
configuration data from a list of strings. To load configuration data as
strings, include the appropriate load
argument and the
lines
argument. The lines
argument takes a
list of strings containing the configuration data to load.
The module attempts to auto-detect the format of the lines
configuration data. However, you can explicitly specify the format by including
the format
argument. For information about specifying the
format, see How to Specify the Format of the Configuration Data to Load. If you
include the format
argument, it overrides the auto-detected
format.
The following playbook configures and commits two op scripts. In this case, the
load
argument has the value 'set'
, because
the configuration data in lines
uses Junos OS
set
statement format.
--- - name: "Load and commit configuration" hosts: dc1 connection: local gather_facts: no tasks: - name: "Load configuration data using strings and commit" juniper.device.config: load: "set" lines: - "set system scripts op file bgp.slax" - "set system scripts op file bgp-neighbor.slax" register: response - name: "Print the response" ansible.builtin.debug: var: response
The following playbook configures the same statements using
lines
with configuration data in text format. In this case,
load: "merge"
is used.
--- - name: "Load and commit configuration" hosts: dc1 connection: local gather_facts: no tasks: - name: "Load configuration data using strings and commit" juniper.device.config: load: "merge" lines: - | system { scripts { op { file bgp.slax; file bgp-neighbor.slax; } } } register: response - name: "Print the response" ansible.builtin.debug: var: response
How to Load Configuration Data from a Local or Remote File
The juniper.device.config
module enables you to load
configuration data from a file. The file can reside in one of the following
locations:
-
Ansible control node
-
Client device
-
URL that is reachable from the client device
When you load configuration data from a file, you must indicate the location of
the file and the format of the configuration data in the file. Supported
configuration data formats include text, Junos XML elements, Junos OS
set
commands, and JSON. For information about loading files
containing Jinja2 templates, see How to Load Configuration Data Using a Jinja2 Template.
You can specify the format of the configuration data either by explicitly
including the format
parameter in the module’s argument list or
by adding the appropriate extension to the configuration data file. If you
specify the format
parameter, it overrides the format indicated
by the file extension. For information about specifying the format, see How to Specify the Format of the Configuration Data to Load. When the configuration
data uses Junos XML format, you must enclose the data in the top-level
<configuration>
tag.
You do not need to enclose configuration data that is formatted as ASCII
text, Junos OS set
commands, or JSON in
<configuration-text>
,
<configuration-set>
, or
<configuration-json>
tags as required when
configuring the device directly within a NETCONF session.
Table 4 outlines the module parameters that you can include to specify the location of the file.
Module Parameter |
Description |
---|---|
|
Absolute or relative path to a file on the Ansible control node. The default directory is the playbook directory. |
|
Absolute or relative path to a file on the client device, or an FTP location or an HTTP URL. The default directory on the client device is the current working directory, which defaults to the user’s home directory. |
To load configuration data from a local file on the Ansible control node, set the
src
argument to the absolute or relative path of the file
containing the configuration data. For example:
--- - name: "Load and commit configuration" hosts: dc1 connection: local gather_facts: no tasks: - name: "Load configuration from a local file and commit" juniper.device.config: load: "merge" src: "build_conf/{{ inventory_hostname }}/junos.conf" register: response - name: "Print the response" ansible.builtin.debug: var: response
To load configuration data from a file on the Junos device or from an FTP or HTTP
URL, use the url
parameter and specify the path of the file
that contains the configuration data to load. For example:
--- - name: "Load and commit configuration" hosts: dc1 connection: local gather_facts: no tasks: - name: "Load configuration from a remote file and commit" juniper.device.config: load: "merge" url: "/var/tmp/junos.conf" register: response - name: "Print the response" ansible.builtin.debug: var: response
The value for url
can be an absolute or relative local file
path, an FTP location, or an HTTP URL.
-
The file path for a local file on the target device has one of the following forms:
-
/path/filename—File on a mounted file system, either on the local flash disk or on hard disk.
-
a:filename or a:path/filename—File on the local drive. The default path is / (the root-level directory). The removable media can be in MS-DOS or UNIX (UFS) format.
-
-
The file path for a file on an FTP server has the following form:
ftp://username:password@hostname/path/filename
-
The file path for a file on an HTTP server has the following form:
http://username:password@hostname/path/filename
In each case, the default value for the path variable is the home directory for the user. To specify an absolute path, the application starts the path with the characters %2F; for example, ftp://username:password@hostname/%2Fpath/filename.
How to Load Configuration Data Using a Jinja2 Template
The juniper.device.config
module enables you to render
configuration data from a Jinja2 template file on the Ansible control node and
load and commit the configuration on a Junos device. 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 Ansible module uses the Jinja2
template and a supplied dictionary of variables to render the configuration
data.
To load and commit configuration data using a Jinja2 template, include the
template
and vars
parameters in the
module’s argument list.
-
template
—Path of the Jinja2 template file -
vars
—Dictionary of keys and values that are required to render the Jinja2 template
You must also include the format
parameter when the template’s
file extension does not indicate the format of the data. For information about
specifying the format, see How to Specify the Format of the Configuration Data to Load.
For example, the interfaces-mpls.j2 file contains the following Jinja2 template:
interfaces { {% for item in interfaces %} {{ item }} { description "{{ description }}"; unit 0 { family {{ family }}; } } {% endfor %} } protocols { mpls { {% for item in interfaces %} interface {{ item }}; {% endfor %} } rsvp { {% for item in interfaces %} interface {{ item }}; {% endfor %} } }
To use the juniper.device.config
module to load the Jinja2
template, set the template
argument to the path of the template
file and define the variables required by the template in the
vars
dictionary. The following playbook uses the Jinja2
template and the variables defined in vars
to render the
configuration data and load and commit it on the target host. The
format
parameter indicates the format of the configuration
data in the template file.
--- - name: "Load and commit configuration" hosts: dc1 connection: local gather_facts: no tasks: - name: "Load a configuration from a Jinja2 template and commit" juniper.device.config: load: "merge" template: "build_conf/templates/interfaces-mpls.j2" format: "text" vars: interfaces: ["ge-1/0/1", "ge-1/0/2", "ge-1/0/3"] description: "MPLS interface" family: "mpls" register: response - name: "Print the response" ansible.builtin.debug: var: response
The module 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; interface ge-1/0/2; interface ge-1/0/3; } rsvp { interface ge-1/0/1; interface ge-1/0/2; interface ge-1/0/3; } }
How to Load the Rescue Configuration
A rescue configuration enables you to define a known working configuration or a configuration with a known state that you can restore at any time. You use the rescue configuration when you need to revert to a known configuration or as a last resort if the device configuration and the backup configuration files become damaged beyond repair. When you create a rescue configuration, the device saves the most recently committed configuration as the rescue configuration.
The juniper.device.config
module enables you to revert to an
existing rescue configuration on Junos devices. To load and commit the rescue
configuration on a device, include the module’s
rollback: "rescue"
argument. For example:
--- - name: "Revert to rescue configuration" hosts: dc1a connection: local gather_facts: no tasks: - name: "Load and commit rescue configuration" juniper.device.config: rollback: "rescue" register: response - name: "Print response" ansible.builtin.debug: var: response
How to Roll Back the Configuration
Junos devices 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 juniper.device.config
module enables you to roll back to a
previously committed configuration on Junos devices. To roll back the
configuration and commit it, include the module’s rollback
argument, and specify the ID of the 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).
The following playbook prompts for the rollback ID of the configuration to restore, rolls back the configuration and commits it, and then prints the configuration changes to standard output:
--- - name: "Roll back the configuration" hosts: dc1a connection: local gather_facts: no vars_prompt: - name: "ROLLBACK" prompt: "Rollback ID of the configuration to restore" private: no tasks: - name: "Roll back the configuration and commit" juniper.device.config: rollback: "{{ ROLLBACK }}" register: response - name: "Print the configuration changes" ansible.builtin.debug: var: response.diff_lines
user@ansible-cn:~/ansible$ ansible-playbook configuration-rollback.yaml Rollback ID of the configuration to restore: 1 PLAY [Roll back the configuration] ******************************************** TASK [Roll back the configuration and commit] ********************************* changed: [dc1a.example.net] TASK [Print the configuration changes] *************************************** ok: [dc1a.example.net] => { "response.diff_lines": [ "", "[edit interfaces]", "- ge-0/0/0 {", "- unit 0 {", "- family mpls;", "- }", "- }" ] } PLAY RECAP ******************************************************************** dc1a.example.net : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
How to Commit the Configuration
By default, when you use the juniper.device.config
module to
modify the configuration using either the load
or the
rollback
argument, the module automatically performs a
commit check and commits the changes. To prevent the module from performing a
commit check or from committing the changes, set the check
or
commit
argument to false
,
respectively.
You can also customize the commit operation with many of the same options that are available in the Junos OS CLI. Table 5 outlines the module arguments that you can use to specify different commit options.
Module Argument |
Description |
Default value for |
---|---|---|
|
Perform a commit check or confirm a previous confirmed commit operation. |
|
|
Wait the specified number of seconds between the commit check and the commit operation. |
– |
|
Log a comment for that commit operation in the system log file and in the device’s commit history. |
– |
|
Commit the configuration changes or confirm a previous confirmed commit operation. |
|
|
Commit the configuration changes even if there are no differences between the candidate configuration and the committed configuration. |
|
|
Synchronize and commit the configuration on all Routing Engines, even if there are open configuration sessions or uncommitted configuration changes on the other Routing Engine. |
|
|
Synchronize and commit the configuration on all Routing Engines. |
|
|
Require that a commit operation be confirmed within a specified amount of time after the initial commit. If the commit is not confirmed in the specified time, roll back to the previously committed configuration. Either the |
– |
|
Wait for completion of the operation using the specified value as the timeout. |
30 seconds |
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: "comment string"
argument with the message string.
Commit Check
By default, the config
module executes both a commit check and a
commit operation. The check_commit_wait
argument defines the
number of seconds to wait between the commit check and commit operations.
Include this argument when you need to provide sufficient time for the device to
complete the commit check operation and release the configuration lock before
initiating the commit operation. If you omit the
check_commit_wait
argument, there might be certain
circumstances in which a device initiates the commit operation before the commit
check operation releases its lock on the configuration, resulting in a
CommitError
and failed commit operation.
Commit Empty Changes
By default, if there are no differences between the candidate configuration and
the committed configuration, the module does not commit the changes. To force a
commit operation even when there are no differences, include the
commit_empty_changes: true
argument.
Commit Synchronize
If the device has dual Routing Engines, you can synchronize and commit the
configuration on both Routing Engines by including the
commit_sync: true
argument. 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 commit_force_sync: true
argument. When
you include the commit_force_sync: true
option, the device
terminates any configuration sessions on the other Routing Engine before
synchronizing and committing the configuration.
Commit Confirm
To require that a commit operation be confirmed within a specified amount of time
after the initial commit, include the
confirmed: minutes
argument. If the
commit is not confirmed within the given time limit, the configuration
automatically rolls back to the previously committed configuration. The allowed
range is 1 through 65,535 minutes. 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 enables access to
the device after the rollback deadline passes. To confirm the commit operation,
invoke the config
module with the check: true
or commit: true
argument.
In the following playbook, the first task modifies the configuration, waits 10
seconds between the commit check and the commit operation, and requires that the
commit operation be confirmed within 5 minutes. It also logs a comment for the
commit. The second task issues a commit check
operation to
confirm the commit. In a real-world scenario, you might perform validation tasks
after the initial commit and only execute the commit confirmation if the tasks
pass certain validation criteria.
--- - name: "Load configuration and confirm within 5 minutes" hosts: dc1 connection: local gather_facts: no tasks: - name: "Load configuration. Wait 10 seconds between check and commit. Confirm within 5 min." juniper.device.config: load: "merge" format: "text" src: "build_conf/{{ inventory_hostname }}/junos.conf" check_commit_wait: 10 confirmed: 5 comment: "updated using Ansible" register: response - name: "Print the response" ansible.builtin.debug: var: response - name: "Confirm the commit with a commit check" juniper.device.config: check: true diff: false commit: false register: response - name: "Print the response" ansible.builtin.debug: var: response
How to Ignore Warnings When Configuring Devices
The juniper.device.config
module enables you to modify and
commit the configuration on Junos devices. In some cases, the RPC reply might
contain <rpc-error>
elements with a severity level of
warning or higher that cause the module to raise an RpcError
exception. An RpcError
exception can cause the load or commit
operation to fail.
In certain cases, it might be necessary or desirable to suppress the
RpcError
exceptions that are raised in response to warnings
for load and commit operations. You can instruct the config
module to suppress RpcError
exceptions that are raised for
warnings by including the ignore_warning
parameter in the
module’s argument list. The ignore_warning
argument takes a
Boolean, a string, or a list of strings.
To instruct the module to ignore all warnings for load and commit operations
performed by the module, include the ignore_warning: true
argument. The following example ignores all warnings for load and commit
operations.
--- - name: Configure Device hosts: dc1 connection: local gather_facts: no tasks: - name: Configure op script juniper.device.config: config_mode: "private" load: "set" lines: - "set system scripts op file bgp.slax" ignore_warning: true register: response - name: Print the response ansible.builtin.debug: var: response
If you include ignore_warning: true
and all of the
<rpc-error>
elements have a severity level of
warning, the application ignores all warnings and does not raise an
RpcError
exception. However, any
<rpc-error>
elements with higher severity levels will
still raise exceptions.
To instruct the module to ignore specific warnings, set the
ignore_warning
argument to a string or a list of strings
containing the warnings to ignore. The following example ignores two specific
warnings:
--- - name: Configure Device hosts: dc1 connection: local gather_facts: no tasks: - name: Configure Junos device and ignore warnings juniper.device.config: config_mode: "private" load: "merge" src: "build_conf/{{ inventory_hostname }}/junos.conf" ignore_warning: - "Advertisement-interval is less than four times" - "Chassis configuration for network services has been changed." register: response - name: Print the response ansible.builtin.debug: var: response
The module suppresses RpcError
exceptions if all of the
<rpc-error>
elements have a severity level of warning
and each warning in the response matches one or more of the specified strings.
Example: Use Ansible to Configure Junos Devices
The juniper.device.config
module enables you to manage the
configuration on Junos devices. This example uses the config
module to
make configuration changes on a Junos device through NETCONF over SSH.
Requirements
This example uses the following hardware and software components:
-
Configuration management server running Ansible 2.10 or later with the
juniper.device
collection installed -
Junos device with NETCONF enabled and a user account configured with appropriate permissions
-
SSH public/private key pair configured for the appropriate user on the Ansible controller and the Junos device
-
Existing Ansible inventory file with required hosts defined
Overview
This example presents an Ansible playbook that uses the
juniper.device.config
module to enable a new op script in the
configuration of the target Junos devices. The configuration data file,
junos-config.conf, contains the relevant configuration data
formatted as text.
The playbook includes the Check NETCONF connectivity
task, which
utilizes the ansible.builtin.wait_for
Ansible module to try to
establish a NETCONF session with the target device using the NETCONF default port
(830). If the control node fails to establish a NETCONF session with a target device
during playbook execution, then it skips the remaining tasks in the play for that
device.
The playbook uses the juniper.device.file_copy
module to copy the
new op script from the Ansible control node to the Junos device. The module
arguments specify the directory and filename of the script on the local device and
the destination directory on the remote device.
The task to configure the device executes the juniper.device.config
module provided that the NETCONF check was successful. The load:
"merge"
argument loads the new configuration data into the candidate
configuration using a load merge
operation. By default, the
config
module commits configuration data on a device for
load
and rollback
operations. The module
arguments include the comment
argument, which records a commit
comment in the device’s system log file and commit history.
Configuration
Create the Configuration Data File
Step-by-Step Procedure
To create the configuration data file that is used by the module:
Create a new file with the appropriate extension based on the format of the configuration data, which in this example is text.
Include the desired configuration changes in the file.
user@ansible-cn:~/ansible$ cat build_conf/dc1a.example.net/junos-config.conf system { scripts { op { file bgp.slax; } } }
Create the Ansible Playbook
Step-by-Step Procedure
To create a playbook that uses the config
module to make
configuration changes on a Junos device:
Include the playbook boilerplate, which executes the modules locally.
--- - name: Load and commit configuration data on a Junos device hosts: dc1 connection: local gather_facts: no
(Optional) Create a task to verify NETCONF connectivity.
tasks: - name: Check NETCONF connectivity ansible.builtin.wait_for: host: "{{ inventory_hostname }}" port: 830 timeout: 5
Create a task to copy the new op script to the device.
- name: Copy the op script to the device juniper.device.file_copy: action: put file: bgp.slax local_dir: scripts remote_dir: /var/db/scripts/op
Create the task to load the configuration onto the device and commit it.
- name: Merge configuration data from a file and commit juniper.device.config: load: "merge" src: "build_conf/{{ inventory_hostname }}/junos-config.conf" comment: "Configuring op script with Ansible" register: response
(Optional) Create a task to print the response, which includes the configuration changes in diff format.
- name: Print the response ansible.builtin.debug: var: response
Results
On the Ansible control node, review the completed playbook. If the playbook does not display the intended code, repeat the instructions in this example to correct the playbook.
--- - name: Load and commit configuration data on a Junos device hosts: dc1 connection: local gather_facts: no tasks: - name: Check NETCONF connectivity ansible.builtin.wait_for: host: "{{ inventory_hostname }}" port: 830 timeout: 5 - name: Copy the op script to the device juniper.device.file_copy: action: put file: bgp.slax local_dir: scripts remote_dir: /var/db/scripts/op - name: Merge configuration data from a file and commit juniper.device.config: load: "merge" src: "build_conf/{{ inventory_hostname }}/junos-config.conf" comment: "Configuring op script with Ansible" register: response - name: Print the response ansible.builtin.debug: var: response
Execute the Playbook
To execute the playbook:
-
Issue the
ansible-playbook
command on the control node, and provide the playbook path and any desired options.user@ansible-cn:~/ansible$ ansible-playbook ansible-pb-junos-config.yaml PLAY [Load and commit configuration data on a Junos device] *************** TASK [Check NETCONF connectivity] ***************************************** ok: [dc1a.example.net] TASK [Copy the op script to the device] *********************************** changed: [dc1a.example.net] TASK [Merge configuration data from a file and commit] ******************** changed: [dc1a.example.net] TASK [Print the response] ************************************************* ok: [dc1a.example.net] => { "response": { "changed": true, "diff": { "prepared": "\n[edit system scripts op]\n+ file bgp.slax;\n" }, "diff_lines": [ "", "[edit system scripts op]", "+ file bgp.slax;" ], "failed": false, "file": "build_conf/dc1a.example.net/junos-config.conf", "msg": "Configuration has been: opened, loaded, checked, diffed, committed, closed." } } PLAY RECAP **************************************************************** dc1a.example.net : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verification
Verify the Configuration
Purpose
Verify that the configuration was correctly updated on the Junos device.
Action
Review the Ansible playbook output to see whether the configuration task succeeded or failed. You can also log in to the Junos device and view the configuration, commit history, and log files to verify the configuration and commit, for example:
user@dc1a> show configuration system scripts op { file bgp.slax; }
user@dc1a> show system commit 0 2020-12-17 15:33:50 PST by user via netconf Configuring op script with Ansible
user@dc1a> show log messages Dec 17 15:33:39 dc1a mgd[33444]: UI_COMMIT: User 'user' requested 'commit' operation (comment: Configuring op script with Ansible) Dec 17 15:33:57 dc1a mgd[33444]: UI_COMMIT_COMPLETED: commit complete
Troubleshoot Playbook Errors
- Troubleshoot Timeout Errors
- Troubleshoot Configuration Lock Errors
- Troubleshoot Configuration Change Errors
Troubleshoot Timeout Errors
Problem
The playbook generates a TimeoutExpiredError
error message
and fails to update the device configuration.
ncclient.operations.errors.TimeoutExpiredError: ncclient timed out while waiting for an rpc reply
The default time for a NETCONF 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.
Solution
To accommodate configuration changes that might require a commit time that is
longer than the default RPC timeout interval, set the module’s
timeout
argument to an appropriate value and re-run the
playbook.
Troubleshoot Configuration Lock Errors
Problem
The playbook generates a LockError
error message indicating
that the configuration cannot be locked. For example:
FAILED! => {"changed": false, "msg": "Unable to open the configuration in exclusive mode: LockError(severity: error, bad_element: None, message: configuration database modified)"}
or
FAILED! => {"changed": false, "msg": "Unable to open the configuration in exclusive mode: LockError(severity: error, bad_element: lock-configuration, message: permission denied)"}
A configuration lock error can occur for the following reasons:
-
Another user has an exclusive lock on the configuration.
-
Another user made changes to the configuration database but has not yet committed the changes.
-
The user executing the Ansible module does not have permissions to configure the device.
Solution
The LockError
message string usually indicates the root
cause of the issue. If another user has an exclusive lock on the
configuration or has modified the configuration, wait until the lock is
released or the changes are committed, and execute the playbook again. If
the cause of the issue is that the user does not have permissions to
configure the device, either execute the playbook with a user who has the
necessary permissions, or if appropriate, configure the Junos device to give
the current user the necessary permissions to make the changes.
Troubleshoot Configuration Change Errors
Problem
The playbook generates a ConfigLoadError
error message
indicating that the configuration cannot be modified, because permission is
denied.
FAILED! => {"changed": false, "msg": "Failure loading the configuraton: ConfigLoadError(severity: error, bad_element: scripts, message: error: permission denied)"}
This error message is generated when the user executing the Ansible module has permission to alter the configuration but does not have permission to alter the requested section of the configuration.
Solution
Either execute the playbook with a user who has the necessary permissions, or if appropriate, configure the Junos device to give the current user the necessary permissions to make the changes.