示例:使用 Junos PyEZ 从文件加载配置数据
Junos PyEZ 库使您能够在 Junos 设备上执行操作和配置任务。此示例使用 Junos PyEZ jnpr.junos.utils.config.Config
实用程序将配置数据从配置管理服务器上的本地文件加载到 Junos 设备上。
要求
此示例使用以下硬件和软件组件:
运行 Python 3.5 或更高版本以及 Junos PyEZ 2.0 或更高版本的配置管理服务器
启用了 NETCONF 且用户帐户配置了适当权限的 Junos 设备
为服务器和 Junos 设备上的相应用户配置的 SSH 公钥/私钥对
概述
此示例演示了一个 Python 应用程序,该应用程序使用 Junos PyEZ Config
实用程序在指定设备的配置中启用新的操作脚本。 junos-config-add-op-script.conf 文件位于配置管理服务器上,其中包含格式化为 ASCII 文本的相关配置数据。
Python 应用程序导入 Device
处理与 Junos 设备的连接的类;用于在目标设备上进行非结构化配置更改的类; Config
以及模块中 jnpr.junos.exception
所需的例外,其中包含管理 Junos 设备时遇到的异常。此示例将 Config
实例绑定到 Device
实例,而不是为类的 Config
实例创建独立变量。
为目标设备创建 Device
实例后, open()
该方法将与设备建立连接和 NETCONF 会话。然后, Config
实用程序方法锁定候选配置,将配置更改作为操作加载 load merge
到候选配置中,提交候选配置,然后将其解锁。
load()
方法path
参数设置为配置文件的路径。由于配置文件扩展名指示配置数据的格式,format
因此参数列表中省略该参数。设置merge=True
指示设备应执行操作load merge
。
配置操作完成后,应用程序将调用该方法 close()
终止 NETCONF 会话和连接。该应用程序包含用于处理异常的代码,例如 LockError
锁定配置时发生的错误和 CommitError
提交操作期间发生的错误。该应用程序还包括用于处理可能发生的任何其他异常的代码。
配置
创建配置数据文件
分步过程
要创建 Junos PyEZ 应用程序使用的配置数据文件,请执行以下操作:
根据配置数据的格式(在此示例中为 ASCII 文本)创建具有相应扩展名的新文件。
在文件中包括所需的配置更改,例如:
system { scripts { op { file bgp-neighbors.slax; } } }
创建 Junos PyEZ 应用程序
分步过程
要创建使用 Junos PyEZ 在 Junos 设备上进行配置更改的 Python 应用程序,请执行以下操作:
导入任何必需的模块、类和对象。
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'
创建
main()
函数定义和函数调用,并将其余语句放在定义中。def main(): if __name__ == "__main__": main()
创建类的
Device
实例,并提供主机名和该特定连接所需的任何参数。然后打开连接并与该设备建立 NETCONF 会话。
# 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
将
Config
实例绑定到Device
实例。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))
结束 NETCONF 会话并关闭与设备的连接。
# End the NETCONF session and close the connection dev.close()
结果
在配置管理服务器上,查看已完成的应用程序。如果应用程序未显示预期的代码,请重复此示例中的说明以更正应用程序。
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()
执行 Junos PyEZ 应用程序
执行应用程序
-
在配置管理服务器上,执行应用程序。
user@server:~$ python3 junos-pyez-config.py Locking the configuration Loading configuration changes Committing the configuration Unlocking the configuration
验证
验证配置
目的
验证 Junos 设备上的配置是否已正确更新。
行动
登录到 Junos 设备并查看配置、提交历史记录和日志文件,以验证配置和提交。例如:
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
意义
配置和日志文件内容指示已在设备上成功配置和提交正确的配置语句。
故障 排除
排查超时错误
问题
Junos PyEZ 代码生成 Rpc超时错误消息或超时过期错误消息,但无法更新设备配置。
RpcTimeoutError(host: dc1a.example.com, cmd: commit-configuration, timeout: 30)
NETCONF RPC 超时的默认时间为 30 秒。大型配置更改可能会超过此值,从而导致操作在上载和提交配置之前超时。
解决 方案
若要适应可能需要提交时间长于默认超时间隔的配置更改,请将超时间隔设置为适当的值,然后重新运行代码。若要配置间隔,请将属性设置为Device
timeout
适当的值,或者在调用commit()
方法以在设备上提交配置数据时包含timeout=seconds
参数。例如:
dev = Device(host="host") dev.open() dev.timeout = 300 ... dev.cu.commit(timeout=360)
排查配置锁定错误
问题
Junos PyEZ 代码会生成一条 LockError 消息,指示无法锁定配置。例如:
LockError(severity: error, bad_element: None, message: configuration database modified)
发生配置锁定错误的原因如下:
另一个用户对配置具有独占锁定。
共享配置数据库具有未提交的更改。
执行 Junos PyEZ 代码的用户没有配置设备的权限。
解决 方案
如果其他用户对配置具有独占锁或修改了配置,请等待锁定释放或更改提交,然后再次执行代码。如果问题的原因是用户没有配置设备的权限,请使用具有必要权限的用户执行应用程序,或者配置Junos 设备以授予当前用户进行更改所需的权限(如果适用)。