Example: Use Junos PyEZ to Load Configuration Data from a File
The Junos PyEZ library enables you to perform operational and configuration tasks on Junos
devices. This example uses the Junos PyEZ
jnpr.junos.utils.config.Config
utility to load configuration data from a local file on the configuration
management server onto a Junos device.
Requirements
This example uses the following hardware and software components:
Configuration management server running Python 3.5 or later and Junos PyEZ Release 2.0 or later
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 server and Junos device
Overview
This example presents a Python application that uses the Junos PyEZ Config
utility to enable a new op script in the configuration of the specified device. The
junos-config-add-op-script.conf file, which is located on
the configuration management server, contains the relevant configuration data
formatted as ASCII text.
The Python application imports the Device
class, which handles the connection
with the Junos device; the Config
class, which is used to make
unstructured configuration changes on the target device; and required exceptions
from the jnpr.junos.exception
module, which contains exceptions
encountered when managing Junos devices. This example binds the
Config
instance to the Device
instance rather
than creating a standalone variable for the instance of the Config
class.
After creating the Device
instance
for the target device, the open()
method establishes a connection and NETCONF
session with the device. The Config
utility
methods then lock the candidate configuration, load the configuration
changes into the candidate configuration as a load merge
operation, commit the candidate configuration, and then unlock it.
The load()
method path
parameter is set to the path of the configuration file. Because
the configuration file extension indicates the format of the configuration
data, the format
parameter is omitted from
the argument list. Setting merge=True
indicates
that the device should perform a load merge
operation.
After the configuration operations are complete, the application calls the
close()
method to terminate the NETCONF session and connection. The application
includes code for handling exceptions such as LockError
for errors
that occur when locking the configuration and CommitError
for
errors that occur during the commit operation. The application also includes code to
handle any additional exceptions that might occur.
Configuration
Create the Configuration Data File
Step-by-Step Procedure
To create the configuration data file that is used by the Junos PyEZ application:
Create a new file with the appropriate extension based on the format of the configuration data, which in this example is ASCII text.
Include the desired configuration changes in the file, for example:
system { scripts { op { file bgp-neighbors.slax; } } }
Create the Junos PyEZ Application
Step-by-Step Procedure
To create a Python application that uses Junos PyEZ to make configuration changes on a Junos device:
Import any required modules, classes, and objects.
from jnpr.junos import Device from jnpr.junos.utils.config import Config from jnpr.junos.exception import ConnectError from jnpr.junos.exception import LockError from jnpr.junos.exception import UnlockError from jnpr.junos.exception import ConfigLoadError from jnpr.junos.exception import CommitError
Include any required variables, which for this example includes the hostname of the managed device and the path to the file containing the configuration data.
host = 'dc1a.example.com' conf_file = 'configs/junos-config-add-op-script.conf'
Create a
main()
function definition and function call, and place the remaining statements within the definition.def main(): if __name__ == "__main__": main()
Create an instance of the
Device
class, and supply the hostname and any parameters required for that specific connection.Then open a connection and establish a NETCONF session with the device.
# open a connection with the device and start a NETCONF session try: dev = Device(host=host) dev.open() except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) return
Bind the
Config
instance to theDevice
instance.dev.bind(cu=Config)
Lock the configuration.
# Lock the configuration, load configuration changes, and commit print ("Locking the configuration") try: dev.cu.lock() except LockError as err: print ("Unable to lock configuration: {0}".format(err)) dev.close() return
Load the configuration changes and handle any errors.
print ("Loading configuration changes") try: dev.cu.load(path=conf_file, merge=True) except (ConfigLoadError, Exception) as err: print ("Unable to load configuration changes: {0}".format(err)) print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError: print ("Unable to unlock configuration: {0}".format(err)) dev.close() return
Commit the configuration.
print ("Committing the configuration") try: dev.cu.commit(comment='Loaded by example.') except CommitError as err: print ("Unable to commit configuration: {0}".format(err)) print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError as err: print ("Unable to unlock configuration: {0}".format(err)) dev.close() return
Unlock the configuration.
print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError as err: print ("Unable to unlock configuration: {0}".format(err))
End the NETCONF session and close the connection with the device.
# End the NETCONF session and close the connection dev.close()
Results
On the configuration management server, review the completed application. If the application does not display the intended code, repeat the instructions in this example to correct the application.
from jnpr.junos import Device from jnpr.junos.utils.config import Config from jnpr.junos.exception import ConnectError from jnpr.junos.exception import LockError from jnpr.junos.exception import UnlockError from jnpr.junos.exception import ConfigLoadError from jnpr.junos.exception import CommitError host = 'dc1a.example.com' conf_file = 'configs/junos-config-add-op-script.conf' def main(): # open a connection with the device and start a NETCONF session try: dev = Device(host=host) dev.open() except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) return dev.bind(cu=Config) # Lock the configuration, load configuration changes, and commit print ("Locking the configuration") try: dev.cu.lock() except LockError as err: print ("Unable to lock configuration: {0}".format(err)) dev.close() return print ("Loading configuration changes") try: dev.cu.load(path=conf_file, merge=True) except (ConfigLoadError, Exception) as err: print ("Unable to load configuration changes: {0}".format(err)) print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError: print ("Unable to unlock configuration: {0}".format(err)) dev.close() return print ("Committing the configuration") try: dev.cu.commit(comment='Loaded by example.') except CommitError as err: print ("Unable to commit configuration: {0}".format(err)) print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError as err: print ("Unable to unlock configuration: {0}".format(err)) dev.close() return print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError as err: print ("Unable to unlock configuration: {0}".format(err)) # End the NETCONF session and close the connection dev.close() if __name__ == "__main__": main()
Execute the Junos PyEZ Application
Execute the Application
-
On the configuration management server, execute the application.
user@server:~$ python3 junos-pyez-config.py Locking the configuration Loading configuration changes Committing the configuration Unlocking the configuration
Verification
Verify the Configuration
Purpose
Verify that the configuration was correctly updated on the Junos device.
Action
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-neighbors.slax; }
user@dc1a> show system commit 0 2014-07-29 14:40:50 PDT by user via netconf ...
user@dc1a> show log messages Jul 29 14:40:36 dc1a sshd[75843]: Accepted publickey for user from 198.51.100.1 port 54811 ssh2: RSA 02:dd:53:3e:f9:97:dd:1f:d9:31:e9:7f:82:06:aa:67 Jul 29 14:40:36 dc1a sshd[75843]: subsystem request for netconf by user user Jul 29 14:40:42 dc1a file[75846]: UI_COMMIT: User 'user' requested 'commit' operation (comment: Loaded by example.) Jul 29 14:40:45 dc1a mspd[75888]: mspd: No member config Jul 29 14:40:45 dc1a mspd[75888]: mspd: Building package info Jul 29 14:40:51 dc1a mspd[1687]: mspd: No member config Jul 29 14:40:51 dc1a mspd[1687]: mspd: Building package info Jul 29 14:40:51 dc1a file[75846]: UI_COMMIT_COMPLETED: commit complete
Meaning
The configuration and the log file contents indicate that the correct configuration statements were successfully configured and committed on the device.
Troubleshooting
- Troubleshoot Timeout Errors
- Troubleshoot Configuration Lock Errors
- Troubleshoot Configuration Change Errors
Troubleshoot Timeout Errors
Problem
The Junos PyEZ code generates an RpcTimeoutError message or a TimeoutExpiredError message and fails to update the device configuration.
RpcTimeoutError(host: dc1a.example.com, cmd: commit-configuration, timeout: 30)
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 timeout interval, set
the timeout interval to an appropriate value and rerun the code. To
configure the interval, either set the Device
timeout
property to an appropriate value,
or include the timeout=seconds
argument when you call the commit()
method
to commit the configuration data on a device. For example:
dev = Device(host="host") dev.open() dev.timeout = 300 ... dev.cu.commit(timeout=360)
Troubleshoot Configuration Lock Errors
Problem
The Junos PyEZ code generates a LockError message indicating that the configuration cannot be locked. For example:
LockError(severity: error, bad_element: None, message: configuration database modified)
A configuration lock error can occur for the following reasons:
Another user has an exclusive lock on the configuration.
The shared configuration database has uncommitted changes.
The user executing the Junos PyEZ code does not have permissions to configure the device.
Solution
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 code again. If the cause of the issue is that the user does not have permissions to configure the device, either execute the application 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 Junos PyEZ code generates a ConfigLoadError message indicating that the configuration cannot be modified due to a permissions issue.
ConfigLoadError(severity: error, bad_element: scripts, message: permission denied)
This error message might be generated when the user executing the Junos PyEZ code has permission to alter the configuration, but does not have permission to alter the desired portion of the configuration.
Solution
Either execute the application 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.