在 CLI 中显示自定义 YANG 模块的有效命令选项和配置语句值
某些 Junos 设备允许您在设备上加载自定义 YANG 模块,以添加不受 Junos OS 本机支持的数据模型。在设备中添加自定义 YANG 数据模型时,还必须提供操作或转换脚本,用于处理 YANG 数据模型与 Junos OS 之间的转换逻辑。尽管脚本逻辑可以确保用户为给定命令选项或配置语句提供有效值,但该逻辑并不总是对用户透明。从 Junos OS 版本 19.2R1 开始,当在选项或语句定义中包含 action-expand
扩展语句并引用用于处理逻辑的脚本时,CLI 会显示自定义 YANG 数据模型中某些命令选项或配置语句的可能值集合。
了解自定义 YANG 模块的环境敏感型帮助
只要您在操作或配置模式下键入问号 (?),Junos CLI 就会提供环境敏感型帮助。执行命令或配置语句时,CLI 的环境敏感型帮助会在配置语句层次结构中显示命令或有效配置语句和叶语句值的有效选项和选项值。此外,环境敏感型帮助显示选项名称、语句名称及其值未完成的可能完成。
CLI 还可以显示对自定义 YANG 数据模型中的某些命令选项或配置语句有效的值。CLI 可以显示所有可能的值或一部分值,这些值与用户的部分输入匹配。例如:
user@host> show host-status hostip ? Possible completions: <hostip> Host IP address 10.10.10.1 IPv4 address 10.10.10.2 IPv4 address 172.16.0.1 IPv4 address 198.51.100.1 IPv4 address 198.51.100.10 IPv4 address 2001:db8::1 IPv6 address (DC 1...128) 2001:db8::fdd2 IPv6 address (DC 1...128)
user@host> show host-status hostip 198? Possible completions: <hostip> Host IP address 198.51.100.1 IPv4 address 198.51.100.10 IPv4 address
要在自定义 YANG 模块中显示给定命令选项或配置语句的有效值集:
-
action-expand
在 YANG 模块中的相应输入参数或配置语句下定义和script
扩展语句,如 定义 YANG 模块所述。 -
创建检查用户输入的 Python 脚本,计算命令选项或配置语句的可能值,并将相应的输出发送至 CLI,如 “创建 CLI 扩展脚本”中所述。
注意:CLI 扩展脚本仅在 CLI 中显示有效值。该模块的转换脚本或操作脚本仍必须包含逻辑,以确保仅接受和处理有效的值。
-
将 YANG 模块、任何转换或操作脚本以及 CLI 扩展脚本加载为设备上自定义 YANG 包的一部分,如 加载 YANG 软件包所述。
注意:Junos 设备将 CLI 扩展脚本处理为另一种操作脚本,但我们指代 CLI 扩展脚本可避免任何混淆。
定义 YANG 模块
要定义自定义 YANG 模块,在用户在 CLI 中请求环境相关帮助时,该模块将显示给定命令选项或配置语句的有效值集,则您的模块必须:
例如,在以下模块中,RPC 定义hostip
了输入参数,当用户请求对语境敏感的 CLI 中的参数帮助hostip
时,该参数称为 hostip-expand.py
Python 脚本。该脚本实施自定义逻辑,在 CLI 中显示该参数的有效值。
module rpc-host-status { namespace "http://yang.juniper.net/examples/rpc-cli"; prefix jrpc; import junos-extension-odl { prefix junos-odl; } import junos-extension { prefix junos; } rpc get-host-status { description "RPC example to retrieve host status"; junos:command "show host-status" { junos:action-execute { junos:script "rpc-host-status.py"; } } input { leaf hostip { description "Host IP address"; type string; junos:action-expand { junos:script "hostip-expand.py"; } } leaf level { type enumeration { enum brief { description "Display brief output"; } enum detail { description "Display detailed output"; } } } } output { ... } } }
创建 CLI 扩展脚本
在自定义 YANG 模块中定义 action-expand
命令选项或配置语句的语句和 script
子陈述,并且要为 CLI 中的该选项或语句值请求上下文敏感的帮助,设备将调用引用的 Python 脚本。脚本必须包含自定义逻辑,用于计算和显示该参数的所有可能值,或显示与用户部分输入匹配的一子值。
例如,以下命令应显示用于该参数的所有有效值 hostip
:
user@host> show host-status hostip ?
以下命令应显示从“198”开始的所有有效值:
user@host> show host-status hostip 198?
要在 CLI 中显示命令选项或配置语句的有效值,Python 脚本应执行以下功能:
-
jcs
将库与其他任何必要的 Python 库一起导入。 -
检索和处理任何用户输入。
如果为 CLI 中的选项或语句值指定部分输入,则脚本的命令行参数包括
symbol
该参数,即包含用户输入的字符串。注意:从 Junos OS 21.2R1 版和 Junos OS Evolved 版本 21.2R1 开始,脚本的命令行参数包括
--symbol
论点而不是symbol
论点。 -
定义或计算参数的有效值。
-
jcs.expand()
调用每个值的功能以显示在命令行上。
脚本必须调用 jcs:expand()
每个选项或语句值的功能,才能在 CLI 中显示。该功能的 jcs:expand()
语法是:
jcs.expand(value, description, <units>, <range>)
地点:
value | 定义给定命令选项或配置语句的有效值的字符串。 |
description | 描述值的字符串。 |
units | (可选)用于定义相应值的单元的字符串。 |
range | (可选)定义相应值范围的字符串。 |
对于功能的每 jcs.expand()
一次调用,脚本都会发出 CLI 中功能参数中提供的值、说明、单元和范围。例如,在脚本中给 jcs.expand()
以下通话:
jcs.expand("2001:db8:4136::fdd2", "IPv6 address", "DC", "1...128")
相应的 CLI 输出为:
Possible completions: <hostip> Host IP address 2001:db8:4136::fdd2 IPv6 address (DC 1...128)
以下示例脚本首先检查脚本的命令行参数是否存在 symbol
,如果存在,则设置的相应变量等于用户的输入。然后脚本根据用户的输入计算参数的有效值集。最后,脚本称为 jcs.expand()
CLI 中显示的每个值的功能。
我们提供了两个版本的脚本,其中适当处理脚本 symbol
对不同版本的论点。以下示例脚本在运行 Junos OS 版本 21.2R1 或更高版本的设备上有效,使用 argparse
库解析 --symbol
该参数。
#!/usr/bin/python3 # Junos OS Release 21.2R1 and later import jcs import argparse parser = argparse.ArgumentParser(description='This is a demo script.') parser.add_argument('--symbol', required=False, default='') args = parser.parse_args() description_ipv4 = "IPv4 address" description_ipv6 = "IPv6 address" expand_colon = ":" expand_units = "DC" expand_range = "1...128" item = ["10.10.10.1", "10.10.10.2", "2001:db8::1", "172.16.0.1", "198.51.100.1", "198.51.100.10", "2001:db8::fdd2"] for ip in item: if ip.startswith(args.symbol) or not args.symbol: if not expand_colon in ip: jcs.expand(ip, description_ipv4) else: jcs.expand(ip, description_ipv6, expand_units, expand_range)
同样,以下示例脚本在运行 Junos OS 版本 21.1 或更低版本的设备上有效,可 symbol
在列表中 sys.argv
检查。
#!/usr/bin/python # Junos OS Release 21.1 and earlier import sys import jcs symbol = "" # Retrieve user input in symbol argument and store the value if "symbol" in sys.argv: index = sys.argv.index("symbol") symbol = sys.argv[index+1] description_ipv4 = "IPv4 address" description_ipv6 = "IPv6 address" expand_colon = ":" expand_units = "DC" expand_range = "1...128" item = ["10.10.10.1", "10.10.10.2", "2001:db8::1", "172.16.0.1", "198.51.100.1", "198.51.100.10", "2001:db8::fdd2"] for ip in item: if ip.startswith(symbol) or not symbol: if not expand_colon in ip: jcs.expand(ip, description_ipv4) else: jcs.expand(ip, description_ipv6, expand_units, expand_range)
CLI 扩展脚本仅显示 CLI 中命令选项或配置语句的有效值、单元和范围。该模块的转换脚本或操作脚本必须确保仅接受和处理有效的值。
加载 YANG 软件包
在 Junos 设备上加载 YANG 软件包时,请在该软件包的操作脚本列表中包含任何 CLI 扩展脚本。Junos OS 会自动将脚本复制到 /var/db/scripts/action directory。
要加载新软件包并包括自定义 CLI 扩展脚本:
示例:显示命令选项的环境敏感型帮助
此示例显示一个自定义 YANG 模块,该模块使用 action-expand
扩展语句和自定义脚本显示其中一个命令选项的可能值集,用户在 CLI 中请求对上下文敏感的帮助,以用于该选项。
要求
此示例使用以下硬件和软件组件:
-
运行 Junos OS 版本 19.2R1 或更高版本的设备,支持加载自定义 YANG 数据模型。
概述
此示例中的 YANG 模块定义了用于对指定主机进行 ping 并返回结果的自定义 RPC。YANG 模块 rpc-host-status
保存在 rpc-host-status.yang 文件中 。该模块导入 Junos OS 扩展模块,提供在设备上执行自定义 RPC 以及自定义 CLI 中的输出和上下文敏感型帮助所需的扩展。
该模块定义get-host-status
了 RPC。语junos:command
句定义用于在 CLI 中执行 RPC 的命令,在这种情况下是 show host-status
。junos:script
和junos:action-execute
语句定义执行 RPC 时调用的操作脚本。
rpc get-host-status { description "RPC example to retrieve host status"; junos:command "show host-status" { junos:action-execute { junos:script "rpc-host-status.py"; } }
输入 hostip
参数包括 junos:action-expand
和 junos:script
语句,用于定义当用户请求该输入参数在 CLI 中对上下文敏感的帮助时调用的脚本。
input { leaf hostip { description "Host IP address"; type string; junos:action-expand { junos:script "hostip-expand.py"; } } ... }
hostip-expand.py 脚本将处理用户的输入,该输入将作为参数symbol
传递至脚本,或者--symbol
根据版本进行。然后,脚本计算并显示用户可为该命令选项输入的一组值。
从 Junos OS 21.2R1 版和 Junos OS Evolved 版本 21.2R1 开始,当设备将命令行参数传递到 Python 操作脚本(包括 CLI 扩展脚本)时,它会将单个连字符 (-) 前缀到单个字符论证名称,并将两个连字符 (--) 前缀到多字符论证名称。
扩展脚本显示 CLI 中的有效值 hostip
。操作脚本实施的逻辑用于确定所提供的值是否有效。此示例会将 YANG 模块和操作脚本添加至设备,作为名为 rpc-host-status
的全新 YANG 软件包的一部分。
YANG 模块和操作脚本
YANG 模块
YANG 模块 rpc-host-status.yang 定义了 RPC、用于在 CLI 中执行 RPC 的命令、执行 RPC 时要调用的操作脚本名称,以及当用户请求对相应输入参数的上下文敏感帮助时调用的 CLI 扩展脚本名称。
/* * Copyright (c) 2019 Juniper Networks, Inc. * All rights reserved. */ module rpc-host-status { namespace "http://yang.juniper.net/examples/rpc-cli"; prefix jrpc; import junos-extension-odl { prefix junos-odl; } import junos-extension { prefix junos; } organization "Juniper Networks, Inc."; description "Junos OS YANG module for RPC example"; rpc get-host-status { description "RPC example to retrieve host status"; junos:command "show host-status" { junos:action-execute { junos:script "rpc-host-status.py"; } } input { leaf hostip { description "Host IP address"; type string; junos:action-expand { junos:script "hostip-expand.py"; } } leaf level { type enumeration { enum brief { description "Display brief output"; } enum detail { description "Display detailed output"; } } } } output { container host-status-information { leaf hostip { type string; description "Host IP"; } leaf status { type string; description "Operational status"; } leaf date { type string; description "Date information"; } junos-odl:style brief { junos-odl:format host-status-information-format-brief { junos-odl:header "Brief output\n"; junos-odl:picture "@<<<<<<<<<<<< @"; junos-odl:space; junos-odl:line { junos-odl:field "hostip"; junos-odl:field "status"; } } } junos-odl:style detail { junos-odl:format host-status-information-format-detail { junos-odl:header "Detail output\n"; junos-odl:picture "@<<<<<<<<<<<< @<<<<<<<<<<<< @"; junos-odl:space; junos-odl:line { junos-odl:field "hostip"; junos-odl:field "status"; junos-odl:field "date"; } } } } } } }
操作脚本
对应的操作脚本 rpc-host-status.py。此示例提供了两个版本的操作脚本,可适当处理不同版本的脚本命令行参数。
操作脚本(Junos OS 版本 21.2R1 和更高版本)
#!/usr/bin/python3 # Junos OS Release 21.2R1 and later import os import argparse parser = argparse.ArgumentParser(description='This is a demo script.') parser.add_argument('--hostip', required=True) parser.add_argument('--level', required=False, default='brief') parser.add_argument('--rpc_name', required=True) args = parser.parse_args() valid_addresses = ["10.10.10.1", "10.10.10.2", "2001:db8::1", "172.16.0.1", "198.51.100.1", "198.51.100.10", "2001:db8::fdd2"] f = os.popen('date') now = f.read() # Ping target host and set the status if args.hostip in valid_addresses: response = os.system('ping -c 1 ' + args.hostip + ' > /dev/null') if response == 0: pingstatus = "Host is Active" else: pingstatus = "Host is Inactive" else: pingstatus = "Invalid host" # Print RPC XML for the given style print ("<host-status-information>") print ("<{}>".format(args.level)) print ("<hostip>{}</hostip>".format(args.hostip)) print ("<status>{}</status>".format(pingstatus)) if args.level == "detail": print ("<date>{}</date>".format(now)) print ("</{}>".format(args.level)) print ("</host-status-information>")
操作脚本(Junos OS 版本 21.1 和更低版本)
#!/usr/bin/python # Junos OS Release 21.1 and earlier import sys import os args = {'hostip': None, 'level': 'brief'} valid_addresses = ["10.10.10.1", "10.10.10.2", "2001:db8::1", "172.16.0.1", "198.51.100.1", "198.51.100.10", "2001:db8::fdd2"] # Retrieve user input and store the values in the args dictionary for arg in args.keys(): if arg in sys.argv: index = sys.argv.index(arg) args[arg] = sys.argv[index+1] f = os.popen('date') now = f.read() # Ping target host and set the status if args['hostip'] in valid_addresses: response = os.system('ping -c 1 ' + args['hostip'] + ' > /dev/null') if response == 0: pingstatus = "Host is Active" else: pingstatus = "Host is Inactive" else: pingstatus = "Invalid host" # Print RPC XML for the given style print ("<host-status-information>") print ("<{}>".format(args['level'])) print ("<hostip>{}</hostip>".format(args['hostip'])) print ("<status>{}</status>".format(pingstatus)) if args['level'] == "detail": print ("<date>{}</date>".format(now)) print ("</{}>".format(args['level'])) print ("</host-status-information>")
CLI 扩展脚本
用于处理用于在 CLI 中显示有效值 hostip
的逻辑的操作脚本 hostip-expand.py。此示例提供了两个版本的脚本,其中适当处理不同版本的脚本参数。
CLI 扩展脚本(Junos OS 版本 21.2R1 和更高版本)
#!/usr/bin/python3 # Junos OS Release 21.2R1 and later import jcs import argparse parser = argparse.ArgumentParser(description='This is a demo script.') parser.add_argument('--symbol', required=False, default='') args = parser.parse_args() description_ipv4 = "IPv4 address" description_ipv6 = "IPv6 address" expand_colon = ":" expand_units = "DC" expand_range = "1...128" item = ["10.10.10.1", "10.10.10.2", "2001:db8::1", "172.16.0.1", "198.51.100.1", "198.51.100.10", "2001:db8::fdd2"] for ip in item: if ip.startswith(args.symbol) or not args.symbol: if not expand_colon in ip: jcs.expand(ip, description_ipv4) else: jcs.expand(ip, description_ipv6, expand_units, expand_range)
CLI 扩展脚本(Junos OS 版本 21.1 和更低版本)
#!/usr/bin/python # Junos OS Release 21.1 and earlier import sys import jcs symbol = "" # Retrieve user input in symbol argument and store the value if "symbol" in sys.argv: index = sys.argv.index("symbol") symbol = sys.argv[index+1] description_ipv4 = "IPv4 address" description_ipv6 = "IPv6 address" expand_colon = ":" expand_units = "DC" expand_range = "1...128" item = ["10.10.10.1", "10.10.10.2", "2001:db8::1", "172.16.0.1", "198.51.100.1", "198.51.100.10", "2001:db8::fdd2"] for ip in item: if ip.startswith(symbol) or not symbol: if not expand_colon in ip: jcs.expand(ip, description_ipv4) else: jcs.expand(ip, description_ipv6, expand_units, expand_range)
配置
支持执行 Python 脚本
要使设备能够执行未签名的 Python 脚本:
-
language python
根据适合 Junos OS 版本配置或language python3
语句。[edit] user@host# set system scripts language (python | python3)
注意:从 Junos OS 20.2R1 版和 Junos OS Evolved 版本 22.3R1 开始,设备使用 Python 3 执行 YANG 操作和转换脚本。在早期版本中,Junos OS 仅使用 Python 2.7 执行这些脚本,而 Junos OS Evolved 默认使用 Python 2.7 执行脚本。
-
提交配置。
[edit] user@host# commit and-quit
在设备上加载 YANG 模块和脚本
要将 YANG 模块和脚本添加到 Junos 设备:
-
将 YANG 模块和脚本下载到 Junos 设备。
-
确保 Python 脚本满足以下要求:
-
文件所有者在 Junos OS
super-user
登录类中为 root 或用户。 -
只有文件所有者才有为该文件写入许可。
-
脚本包括 Junos 设备上的 YANG RPC 创建操作脚本中概述的相应解释器指令行。
-
-
(可选)验证 YANG 模块和操作脚本的语法。
user@host> request system yang validate module /var/tmp/rpc-host-status.yang action-script [ /var/tmp/rpc-host-status.py /var/tmp/hostip-expand.py ] YANG modules validation : START YANG modules validation : SUCCESS Scripts syntax validation : START Scripts syntax validation : SUCCESS
-
将 YANG 模块和脚本添加到新的 YANG 包中。
user@host> request system yang add package rpc-host-status module /var/tmp/rpc-host-status.yang action-script [ /var/tmp/rpc-host-status.py /var/tmp/hostip-expand.py ] YANG modules validation : START YANG modules validation : SUCCESS Scripts syntax validation : START Scripts syntax validation : SUCCESS TLV generation: START TLV generation: SUCCESS Building schema and reloading /config/juniper.conf.gz ... mgd: commit complete Restarting mgd ...
-
当系统提示您重新启动 Junos OS CLI 时,按下
Enter
接受默认值,yes
或键入 yes 并按下Enter
。WARNING: cli has been replaced by an updated version: ... Restart cli using the new version ? [yes,no] (yes) yes Restarting cli ...
验证环境敏感型帮助
目的
验证 CLI 扩展脚本是否可根据预期工作。
行动
在操作模式下,在 CLI 中请求环境敏感型帮助,方法是发出由 RPC 定义中的语句定义的 junos:command
命令,并包括 hostip
输入论点和问号 (?)。
user@host> show host-status hostip ? Possible completions: <hostip> Host IP address 10.10.10.1 IPv4 address 10.10.10.2 IPv4 address 172.16.0.1 IPv4 address 198.51.100.1 IPv4 address 198.51.100.10 IPv4 address 2001:db8::1 IPv6 address (DC 1...128) 2001:db8::fdd2 IPv6 address (DC 1...128)
使用部分用户输入执行相同的操作,并验证显示的值是否正确匹配输入。
user@host> show host-status hostip 198? Possible completions: <hostip> Host IP address 198.51.100.1 IPv4 address 198.51.100.10 IPv4 address
意义
请求对上下文敏感的值帮助 hostip
时,设备将调用 hostip-expand.py
脚本。脚本将处理用户的输入(如果提供),并在 CLI 中打印有效完成。如果未提供用户输入,则脚本将打印所有可能的值。提供用户输入时,脚本仅打印匹配值。