Help us improve your experience.

Let us know what you think.

Do you have time for a two-minute survey?

 
 

Use Junos Snapshot Administrator in Python (JSNAPy) in Ansible Playbooks

SUMMARY Execute JSNAPy tests as part of an Ansible playbook to capture and audit runtime environment snapshots of Junos devices.

Junos® Snapshot Administrator in Python (JSNAPy) enables you to capture and audit runtime environment snapshots of your network Junos devices. You can capture and verify the configuration and operational status of a device and verify changes to a device. Juniper Networks provides Ansible modules that enable you to execute JSNAPy tests against Junos devices as part of an Ansible playbook. Table 1 outlines the available modules.

Table 1: JSNAPy Modules

Content Set

Module Name

juniper.device collection

jsnapy

Juniper.junos role

juniper_junos_jsnapy

You must install Junos Snapshot Administrator in Python on the Ansible control node in order to use the modules. For installation instructions and information about creating JSNAPy configuration and test files, see the Junos Snapshot Administrator in Python Documentation.

Note:

Starting in Juniper.junos Release 2.0.0, the juniper_junos_jsnapy module replaces the functionality of the junos_jsnapy module.

The following sections discuss how to use the modules in Ansible playbooks.

Module Overview

The jsnapy and juniper_junos_jsnapy modules enable you to execute many of the same JSNAPy functions from an Ansible playbook as you can execute using JSNAPy on the command line, including:

  • capturing and saving a runtime environment snapshot

  • comparing two snapshots

  • capturing a snapshot and immediately evaluating it

The modules require specifying the action argument and either the config_file or the test_files argument. The action argument specifies the JSNAPy action to perform. Table 2 outlines the valid action values and the equivalent JSNAPy commands.

Table 2: jsnapy and juniper_junos_jsnapy action Argument Values

action Value

Description

Equivalent JSNAPy Command

check

Compare two existing snapshots based on the given test cases, or if no test cases are supplied, compare the snapshots node by node.

jsnapy --check

snap_post

Take snapshots for the commands or RPCs specified in the test files after making changes on the given devices.

jsnapy --snap

snap_pre

Take snapshots for the commands or RPCs specified in the test files prior to making changes on the given devices.

jsnapy --snap

snapcheck

Take snapshots of the commands or RPCs specified in the test files and immediately evaluate the snapshots against pre-defined criteria in the test cases.

jsnapy --snapcheck

When you execute JSNAPy on the command line, JSNAPy performs the requested action on the hosts specified in the hosts section of the configuration file. In contrast, the Ansible modules execute the requested action on the hosts in the Ansible inventory group defined in the playbook. As a result, the module can either reference a configuration file, ignoring the hosts section, or it can directly reference one or more test files.

Thus, in addition to the action argument, the jsnapy and juniper_junos_jsnapy modules also require either the config_file or the test_files argument to specify the JSNAPy configuration file or the JSNAPy test files to use for the given action. Table 3 outlines the config_file and test_files arguments.

Table 3: jsnapy and juniper_junos_jsnapy File Arguments

Module argument

Value

Additional Information

config_file

Absolute or relative file path to a JSNAPy configuration file.

If the path is relative, the module checks for the configuration file in the following locations and in the order indicated:

  • Ansible playbook directory

  • dir argument directory, if provided

  • /etc/jsnapy/testfiles directory (only if the dir argument is omitted)

If the configuration file references test files by using a relative file path, the module first checks for the test files in the playbook directory and then checks for the test files in the default testfiles directory, which will vary depending on the JSNAPy release and your environment.

test_files

Absolute or relative file path to a JSNAPy test file. This can be a single file path or a list of file paths.

For each test file that specifies a relative path, the module checks for the file in the following locations and in the order indicated:

  • Ansible playbook directory

  • dir argument directory, if provided

  • /etc/jsnapy/testfiles directory (only if the dir argument is omitted)

The config_file and test_files arguments can take an absolute or relative file path. When using a relative file path, you can optionally include the dir module argument to specify the directory in which the files reside. If a config_file or test_files argument uses a relative file path, the module first checks for the file under the Ansible playbook directory, even if the dir argument is present. If the file does not exist under the playbook directory, the module checks under the dir argument directory, if it is specified, or under the /etc/jsnapy/testfiles directory, if the dir argument is omitted. The playbook generates an error message if the file is not found.

The following sample playbook performs the snap_pre action using the configuration_interface_status.yaml configuration file. If the configuration file does not exist in the playbook directory, the module checks for the file in the user’s home directory under the jsnapy/testfiles subdirectory.

Note:

Starting in Junos Snapshot Administrator in Python Release 1.3.0, the default location for configuration and test files is ~/jsnapy/testfiles. However, the default location inside a virtual environment or for earlier releases is /etc/jsnapy/testfiles.

The module performs the requested action on the hosts specified in the Ansible playbook, even if the module references a configuration file that includes a hosts section. The module reports failed if it encounters an error and fails to execute the JSNAPy tests. It does not report failed if one or more of the JSNAPy tests fail. To check the JSNAPy test results, register the module’s response, and use the assert module to verify the expected result in the response.

Junos Snapshot Administrator in Python logs information regarding its operations to the /var/log/jsnapy/jsnapy.log file by default. The jsnapy and juniper_junos_jsnapy modules can optionally include the logfile argument, which specifies the path to a writable file on the Ansible control node where information for the particular task is logged. The level of information logged in the file is determined by Ansible’s verbosity level and debug options. By default, only messages of severity level WARNING or higher are logged. To log messages equal to or higher than severity level INFO or severity level DEBUG, execute the playbook with the -v or -vv command-line option, respectively.

When you execute JSNAPy tests in an Ansible playbook, you can enable the jsnapy callback plugin to capture and summarize information for failed JSNAPy tests. To enable the callback plugin, add the callback_whitelist = jsnapy statement to the Ansible configuration file. For more information, see Enable the jsnapy Callback Plugin.

Take and Compare Snapshots

JSNAPy enables you to capture runtime environment snapshots of your network Junos devices before and after a change and then compare the snapshots to verify the expected changes or identify unexpected issues. The jsnapy and juniper_junos_jsnapy Ansible modules enable you to take and compare JSNAPy snapshots as part of an Ansible playbook. The modules save each snapshot for each host in a separate file in the default JSNAPy snapshot directory using a predetermined filename. For more information about the output files, see Understanding the jsnapy and juniper_junos_jsnapy Module Output.

To take baseline snapshots of one or more devices prior to making changes, set the module’s action argument to snap_pre, and specify a configuration file or one or more test files.

The following playbook saves PRE snapshots for each device in the Ansible inventory group. The task references the configuration_interface_status.yaml configuration file in the ~/jsnapy/testfiles directory and logs messages to the jsnapy_tests.log file in the playbook directory.

To take a snapshot of one or more devices after performing changes, set the module’s action argument to snap_post, and specify a configuration file or one or more test files.

The following playbook saves POST snapshots for each device in the Ansible inventory group. The task references the same configuration_interface_status.yaml configuration file in the ~/jsnapy/testfiles directory and logs messages to the jsnapy_tests.log file in the playbook directory.

When the jsnapy or juniper_junos_jsnapy module performs a snap_pre action or a snap_post action, it saves each snapshot for each host in a separate file using auto-generated filenames that contain a 'PRE' or 'POST' tag, respectively. To compare the PRE and POST snapshots to quickly verify the updates or identify any issues that might have resulted from the changes, set the module’s action argument to check, and specify the same configuration file or test files that were used to take the snapshots.

When the module performs a check action, the preexisting PRE and POST snapshots for each test on each device are compared and evaluated against the criteria defined in the tests: section of the test files. If the test files do not define any test cases, JSNAPy instead compares the snapshots node by node. To check the test results, register the module’s response, and use the assert module to verify the expected result in the response.

The following playbook compares the snapshots taken for previously executed snap_pre and snap_post actions for every device in the Ansible inventory group. The results are evaluated using the criteria in the test files that are referenced in the configuration file. The playbook registers the module’s response as 'test_result' and uses the assert module to verify that all tests passed on the given device.

When you run the playbook, the assertions quickly identify which devices failed the tests.

Perform Snapcheck Operations

JSNAPy enables you to take snapshots for the commands or RPCs specified in JSNAPy test files and immediately evaluate the snapshots against pre-defined criteria in the test cases. The jsnapy and juniper_junos_jsnapy Ansible modules enable you to perform a JSNAPy snapcheck operation as part of an Ansible playbook.

To take a snapshot and immediately evaluate it based on the pre-defined set of criteria in the tests: section of the test files, set the module’s action argument to snapcheck, and specify a configuration file or one or more test files. To check the test results, register the module’s response, and use the assert module to verify the expected result in the response.

For example, for each device in the Ansible inventory group, the following playbook saves a separate snapshot for each command or RPC in the test files, registers the module’s response, and uses the assert module to verify that all tests defined in the test files passed on that device.

Understanding the jsnapy and juniper_junos_jsnapy Module Output

When the jsnapy or juniper_junos_jsnapy module performs a snap_pre, snap_post, or snapcheck action, it automatically saves the snapshots in the JSNAPy snapshots directory. The modules use the default JSNAPy directories unless you modify the JSNAPy configuration file to specify a different location. The module creates a separate file for each command or RPC executed on each device in the Ansible inventory group. Table 4 outlines the filenames of the snapshot files for each value of the action argument.

Note:

Starting in Junos Snapshot Administrator in Python Release 1.3.0, the default directories for the JSNAPy test files and snapshots are ~/jsnapy/testfiles and ~/jsnapy/snapshots, respectively. However, the default directories inside a virtual environment or for earlier releases are /etc/jsnapy/testfiles and /etc/jsnapy/snapshots.

Table 4: JSNAPy Output Filenames

action value

Output Files

snap_pre

hostname_PRE_hash_command.format

snap_post

hostname_POST_hash_command.format

snapcheck

hostname_snap_temp_hash_command.format
or
hostname_PRE_hash_command.format

where:

  • hostname—Hostname of the device on which the command or RPC is executed.

  • (PRE | POST | snap_temp)—Tag identifying the action. The snapcheck operation uses the PRE tag in current releases; in earlier releases the operation uses the snap_temp tag.

  • hash—Hash generated from kwargs for test files that include the rpc and kwargs keys.

    If test files use the same RPC but include different arguments, and the RPCs are executed on the same host, the hash ensures unique output filenames in those cases. If a test file defines the command key or if a test file defines the rpc key but does not include the kwargs key, the hash is omitted.

  • command—Command or RPC executed on the managed device. The module replaces whitespace and special characters in the command or RPC name with underscores ( _ ).

  • format—Format of the output, for example, xml.

Note:

The jsnapy and juniper_junos_jsnapy modules only differentiate the snapshot filenames for a given action based on hostname and command or RPC. As a result, if the module takes snapshots on the same device for the same action using test files that define the same command or RPC, the module will generate snapshots with the same filename, and the new file will overwrite the old file.

For example, if the module includes action: "snap_pre" and references test files that execute the show chassis fpc and show interfaces terse commands on devices dc1a.example.net and dc1b.example.net, the resulting files are:

If the module includes action: "snap_post" and references a test file that executes the get-interface-information RPC with kwargs item interface_name: lo0 on device dc1a.example.net, the resulting file is:

In addition to generating the snapshot files, the jsnapy and juniper_junos_jsnapy modules can also return the following keys in the module response:

  • action—JSNAPy action performed by the module.

  • changed—Indicates if the device’s state changed. Since JSNAPy only reports on state, the value is always false.

  • failed—Indicates if the playbook task failed.

  • msg—JSNAPy test results.

Enable the jsnapy Callback Plugin

When you execute JSNAPy tests against Junos devices and one or more tests fail, it can be difficult to identify and extract the failed tests if the output is extensive. The jsnapy callback plugin enables you to easily extract and summarize the information for failed JSNAPy tests. When you enable the jsnapy callback plugin and execute a playbook that includes JSNAPy tests, the plugin summarizes the information for the failed JSNAPy tests after the playbook PLAY RECAP.

The jsnapy callback plugin is not enabled by default. To enable the jsnapy callback plugin, add the callback_whitelist = jsnapy statement to the Ansible configuration file.

When you enable the jsnapy callback plugin and run a playbook, the plugin summarizes the failed JSNAPy tests in a human-readable format. For example:

Example: Use Ansible to Perform a JSNAPy Snapcheck Operation

The jsnapy module enables you to execute JSNAPy tests against Junos devices as part of an Ansible playbook. This examples uses the jsnapy module to perform a snapcheck action to verify the operational state of Junos devices after applying specific configuration changes.

Requirements

This example uses the following hardware and software components:

  • Ansible control node running:

    • Python 3.7 or later

    • Ansible 2.10 or later with the juniper.device collection installed

    • Junos PyEZ Release 2.6.0 or later

    • Junos Snapshot Administrator in Python Release 1.3.6 or later

Before executing the Ansible playbook, be sure you have:

  • Junos devices with NETCONF over SSH enabled and a user account configured with appropriate permissions

  • SSH public/private key pair configured for the appropriate user on the Ansible control node and Junos device

  • Existing Ansible inventory file with required hosts defined

Overview

In this example, the Ansible playbook configures BGP peering sessions on three Junos devices and uses the jsnapy module to verify that the BGP session is established for each neighbor address. If the playbook verifies that the sessions are established on a device, it confirms the commit for the new configuration. If the playbook does not confirm the commit, the Junos device automatically rolls back to the previously committed configuration. The Ansible project defines the group and host variables for the playbook under the group_vars and host_vars directories, respectively.

The playbook has two plays. The first play, Load and commit BGP configuration, generates and assembles the configuration, loads the configuration on the device, and commits it using a commit confirmed operation. If the configuration is updated, one handler is notified. The play executes the following tasks:

Remove build directory

Deletes the existing build directory for the given device, if present.

Create build directory

Creates a new, empty build directory for the given device.

Build BGP configuration

Uses the template module with the Jinja2 template and host variables to render the BGP configuration for the given device and save it to a file in the device’s build directory.

Assemble configuration parts

Uses the assemble module to assemble the device configuration file from the files in that device’s build directory.

In this example, only the BGP configuration file will be present, and thus the resulting configuration file is identical to the BGP configuration file rendered in the previous task. If you later add new tasks to generate additional configuration files from other templates, the assemble module will combine all files into a single configuration.

Load and commit config, require confirmation

Loads the configuration onto the Junos device and commits the configuration using a commit confirmed operation, which requires explicit confirmation for the commit to become permanent. If this task makes a change to the configuration, it also notifies the handler that pauses playbook execution for a specified amount of time to allow the BGP peers to establish connections before the second play is executed.

If the requested configuration is already present on the device, the config module does not load and commit the configuration. In this case, the module returns changed: false, and thus does not notify the handler.

The second play, Verify BGP, performs a JSNAPy snapcheck operation on each device using the tests in the JSNAPy test files and confirms the commit, provided that all the tests pass. The play executes the following tasks:

Execute snapcheck

Performs a JSNAPy snapcheck operation, which in this case, validates that the BGP session is established for each of the device’s neighbors and that there are no down peers.

In this example, the playbook directly references JSNAPy test files by setting the test_files argument equal to the list of JSNAPy test files. The dir argument specifies the directory where the test files are stored.

Confirm commit

Executes a commit check operation, which confirms the previous commit operation, provided that the first playbook play updated the configuration and that all of the JSNAPy tests passed. If the playbook updates the configuration but does not confirm the commit, the Junos device automatically rolls the configuration back to the previously committed configuration.

Note:

You can confirm the previous commit operation with either a commit check or commit operation on the device, which corresponds to the check: true or commit: true argument, respectively, in the config module.

Verify BGP configuration

(Optional) Explicitly indicates whether the JSNAPy tests passed or failed on the given device. This task is not specifically required, but it more easily identifies when the JSNAPy tests fail and on which devices.

Configuration

Define the Group Variables

Step-by-Step Procedure

To define the group variables:

  • In the group_vars/all file, define variables for the build directory and for the filenames of the configuration and log files.

Define the Jinja2 Template and Host Variables

Define the Jinja2 Template

To create the Jinja2 template that is used to generate the BGP configuration:

  1. Create a file named bgp-template.j2 in the project’s playbook directory.

  2. Add the BGP configuration template to the file.

Define the Host Variables

To define the host variables that are used with the Jinja2 template to generate the BGP configuration:

  1. In the project’s host_vars directory, create a separate file named hostname.yaml for each host.

  2. Define the variables for host r1 in the r1.yaml file.

  3. Define the variables for host r2 in the r2.yaml file.

  4. Define the variables for host r3 in the r3.yaml file.

Create the JSNAPy Test Files

Step-by-Step Procedure

The jsnapy module references JSNAPy test files in the ~/jsnapy/testfiles directory. To create the JSNAPy test files:

  1. Create the jsnapy_test_file_bgp_states.yaml file, which executes the show bgp neighbor command and tests that the BGP peer state is established.

  2. Create the jsnapy_test_file_bgp_summary.yaml file, which executes the show bgp summary command and asserts that the BGP down peers count must be 0.

Create the Ansible Playbook

Define the First Play to Configure the Device

To create the first play, which renders the configuration, loads it on the device, and commits the configuration as a commit confirmed operation:

  1. Include the boilerplate for the playbook and the first play, which executes the modules locally.

  2. Create the tasks that replace the existing build directory with an empty directory, which will store the new configuration files.

  3. Create the task that renders the BGP configuration from the Jinja2 template file and host variables and stores it in the bgp.conf file in the build directory for that host.

  4. Create a task to assemble the configuration files in the build directory into the final junos.conf configuration file.

  5. Create the task that loads the configuration on the device, performs a commit operation that requires confirmation, and notifies the given handler, provided the configuration was changed.

  6. Create a handler that pauses playbook execution if the device configuration is updated, and set the pause time to an appropriate value for your environment.

Define the Second Play to Perform JSNAPy Operations

To create the second play, which performs a JSNAPy snapcheck operation and confirms the committed configuration, provided that the configuration changed and the JSNAPy tests passed:

  1. Include the boilerplate for the second play, which executes the modules locally.

  2. Create a task to perform a JSNAPy snapcheck operation based on the tests in the given JSNAPy test files, and register the module’s response.

  3. Create the task to confirm the commit provided that the given conditions are met.

  4. (Optional) Create a task that uses the assert module to assert that the JSNAPy tests passed.

Results

On the Ansible control node, review the completed playbook. If the playbook does not display the intended code, repeat the instructions in this section to correct the playbook.

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.

Verification

Verify the BGP Neighbors

Purpose

Verify that the BGP session is established for each neighbor address.

The JSNAPy test files test that the BGP session is established for each neighbor address and that the there are no down peers. The Verify BGP configuration task output enables you to quickly verify that the given device passed all JSNAPy tests. If the JSNAPy passPercentage is equal to 100 percent, the task includes "msg": "All assertions passed" in the task output.

Action

Review the Verify BGP configuration task output, and verify that each device returns the All assertions passed message.

Meaning

The All assertions passed message indicates that the BGP sessions are successfully established on the devices.

Troubleshoot Ansible Playbook Errors

Troubleshoot Configuration Load Errors

Problem

The Ansible playbook generates a ConfigLoadError error indicating that it failed to load the configuration on the device because of a syntax error.

Solution

The playbook renders the Junos OS configuration by using the Jinja2 template and the host variables defined for that device in the host_vars directory. The playbook generates a syntax error when the Jinja2 template produces an invalid configuration. To correct this error, update the Jinja2 template to correct the element identified by the bad_element key in the error message.

Troubleshoot Failed JSNAPy Tests

Problem

The Verify BGP configuration task output indicates that the assertion failed, because the JSNAPy passPercentage was not equal to 100 percent.

The assertion fails when the device has not established the BGP session with its neighbor or the session goes down. If the assertion fails, and the configuration for that device was updated in the first play, the playbook does not confirm the commit for the new configuration on the device, and the device rolls the configuration back to the previously committed configuration.

Solution

The JSNAPy tests might fail if the snapcheck operation is taken before the peers can establish the session or because the BGP neighbors are not configured correctly. If the playbook output indicates that the configuration was successfully loaded and committed on the device, try increasing the handler’s pause interval to a suitable value for your environment and rerun the playbook.

If the tests still fail, verify that the Jinja2 template and the host variables for each device contain the correct data and that the resulting configuration for each device is correct.

Troubleshoot Failed Commit Confirmations

Problem

The configuration was not confirmed on one or more devices.

Solution

The playbook only confirms the configuration if it changed and the JSNAPy tests pass. If the Load and commit config, require confirmation task output indicates that the configuration did not change, the playbook does not execute the task to confirm the commit. If the configuration changed but was not confirmed, then the JSNAPy tests failed. The JSNAPy tests might fail if the BGP neighbors are not configured correctly or if the playbook does not provide enough time between the plays for the devices to establish the BGP session. For more information, see Troubleshoot Failed JSNAPy Tests.

Release History Table
Release
Description
2.0.0
Starting in Juniper.junos Release 2.0.0, the juniper_junos_jsnapy module replaces the functionality of the junos_jsnapy module.