pyangbind, 为YANG模型创建 python 绑定的pyang插件

分享于 

17分钟阅读

GitHub

  繁體 雙語
A plugin for pyang that creates Python bindings for a YANG model.
  • 源代码名称:pyangbind
  • 源代码网址:http://www.github.com/robshakir/pyangbind
  • pyangbind源代码文档
  • pyangbind源代码下载
  • Git URL:
    git://www.github.com/robshakir/pyangbind.git
    Git Clone代码到本地:
    git clone http://www.github.com/robshakir/pyangbind
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/robshakir/pyangbind
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    

    #PyangBind

    PyangBind 是用于 Pyang插件的插件,它从YANG数据模型生成一个 python 类层次结构。 生成的类可以在 python 中直接与之交互。 特别是,PyangBind 将允许你:

    • 通过设置 python 类层次结构中的值来创建新的数据实例。
    • 从外部源加载数据实例- 从外部源获取输入数据,并允许通过 python 类对它的进行寻址。
    • Serialise填充对象可以存储为可以存储的格式或者发送到另一个系统( 比如,一个网络元素)。

    使用的数据模型来开发收费的PyangBind,并针对这些模型进行良好的测试。 生成的python 类,以及,方法用于向网络运算符提供从网络元素加载数据实例的起点。 费费的类还有允许其他方法与类关联的功能,这样就可以将它的用于网管中心的基础。

    电子邮件内容

    启动

    通过 PyPI 分发了英镑 PyangBind,它可以通过运行以下命令安装:

    
    $ pip install pyangbind
    
    
    
    

    pyangbind 模块同时安装Pyang插件( pyangbind.plugin.* ),以及一组用于提供YANG类型的python 表示的库模块( pyangbind.lib.* )。

    生成一组类

    要生成第一组类,需要一个YANG模块及其依赖项。 可以在 tests 目录( 比如,tests/base-test.yang ) 中找到许多简单的模块。

    要生成一组 python 类,Pyang需要提供一个指向pyangbind插件插件的位置的指针。 可以通过运行以下命令找到这里位置:

    
    $ export PYBINDPLUGIN=`/usr/bin/env python -c 
    
    
    'import pyangbind; import os; print ("{}/plugin".format(os.path.dirname(pyangbind.__file__)))'`
    
    
    $ echo $PYBINDPLUGIN
    
    
    
    

    一旦知道这里路径,就可以将它提供给 --plugin-dir 参数以进行 Pyang。 在最简单的形式中,使用的命令是:

    
    $ pyang --plugindir $PYBINDPLUGIN -f pybind -o binding.py tests/base-test.yang
    
    
    
    

    其中:

    • $PYBINDPLUGIN 是从上面的命令导出的位置。
    • binding.py 是所需的输出文件。
    • doc/base-test.yang 是要为它的生成绑定的YANG模块的路径。

    还有许多其他的选项,在 docs/ 目录下进一步讨论。

    使用 python 程序中的类( ) 来使用

    PyangBind 生成( 集合) python 模块。 顶级模块以YANG模块命名- 名称为 python 安全。 通常,附加下划线的附加下划线,并用下划线替换连字符,使 openconfig-local-routing.yang 成为模块名称的openconfig_local_routing

    首先,我们需要为我们感兴趣的模型生成一组类。 本演练将使用OpenConfig本地路由模块作为本演练的示例。

    可以通过运行以下命令来生成绑定 docs/example/oc-local-routing/generate_bindings.sh 脚本简单地使用 curl 来检索模块,然后将绑定构建到上面的binding.py 文件中。

    使用PyangBind类的最简单的程序看起来像:

    # Using the binding file generated by the `generate_bindings.sh` script# Note that CWD is the file containing the binding.py file.# Alternatively, you can use sys.path.append to add the CWD to the PYTHONPATHfrom binding import openconfig_local_routing
    oclr = openconfig_local_routing()

    创建一个数据实例

    这里时,oclr 对象可以用于操作由模块表示的杨数据树。

    openconfig-local-routing的子集类似于下面的树:

    
    module: openconfig-local-routing
    
    
     +--rw local-routes
    
    
    . . .
    
    
     +--rw static-routes
    
    
     | +--rw static* [prefix]
    
    
     | +--rw prefix ->.. /config/prefix
    
    
     | +--rw config
    
    
     | | +--rw prefix? inet:ip-prefix
    
    
     | | +--rw next-hop* union
    
    
    
    

    要向 static 列表添加条目,请使用 static 对象的add 方法:

    rt = oclr.local_routes.static_routes.static.add("192.0.2.1/32")

    static 列表根据它在杨模块中的路径,它是 static-routes 容器( 他的名字被称为 python )的成员,它本身是 local-routes 容器的成员。

    add 方法返回对新创建的列表对象的引用- 这样我们可以使用 rt 对象更改新创建的列表项。 例如可以在路径上设置标记:

    rt.config.set_tag =42

    然后可以通过 rt 对象或者通过原始 oclr 对象( 它们都引用了内存中的同一个对象) 直接访问标记值:

    # Retrieve the tag valueprint(rt.config.set_tag)# output: 42# Retrieve the tag value through the original objectprint(oclr.local_routes.static_routes.static["192.0.2.1/32"].config.set_tag)# output: 42

    此外,表示 container 或者 list 对象的PyangBind类具有特殊的get() 方法。 这将为打印或者调试目的转储对象的字典表示形式。 例如:

    print(oclr.local_routes.static_routes.static["192.0.2.1/32"].get(filter=True))# returns {'prefix': u'192.0.2.1/32', 'config': {'set-tag': 42}}

    filter 关键字只允许类中已经更改( 不是空的或者它们的默认值)的元素输出- 而不是所有可能的元素。

    这里模型中的next-hops 元素是另一个列表。 这个键控数据结构像 python 字典,并且有特殊的方法 add 来向它添加项。 YANG leaf-list 类型使用标准的python 列表 append 方法向它的添加项。 同样,可以使用与字典相同的方法迭代 list,例如使用 iteritems():

    # Add a set of next_hopsfor nhop in [(0, "192.168.0.1"), (1, "10.0.0.1")]:
     nh = rt.next_hops.next_hop.add(nhop[0])
     nh.config.next_hop = nhop[1]# Iterate through the next-hops addedfor index, nh in rt.next_hops.next_hop.iteritems():
     print("{}: {}".format(index, nh.config.next_hop))

    存在( 类型或值) 限制的地方。 PyangBind生成的类将产生 python ValueError。 例如如果尝试将 set_tag 叶设置为无效值:

    # Try and set an invalid tag typetry:
     rt.config.set_tag ="INVALID-TAG"exceptValueErroras m:
     print("Cannot set tag: {}".format(m))

    Serialising数据实例

    显然,填充的PyangBind类并不用于本身- 常用用例是发送到外部系统(。比如,路由器或者其他NMS组件)。 为了达到这个目的,类层次结构需要成为一个可以发送到远程实体的格式。 目前有多种方法可以实现这里目的:

    • 这个映射的规则在 RFC6020bis 中定义- 当前不支持
    • openconfig建议JSON这个映射的规则目前正被写入正式规范中。 这是PyangBind使用的标准( default ) 格式。 一些网络设备供应商使用这种序列化格式。
    • :这个映射的规则定义在 draft-ietf-netmod-yang-json 中,一些网络设备供应商使用这种格式。

    任何PyangBind类都可以被serialised转换为任何支持的格式。 在上面的例子中,整个 local-routing 模块可以使用下面的代码为 static json serialised

    import pyangbind.lib.pybindJSON as pybindJSON# Dump the entire instance as JSON in PyangBind formatprint(pybindJSON.dumps(oclr))

    这将输出以下JSON结构化文本:

    {
     "local-routes": {
     "static-routes": {
     "static": {
     "192.0.2.1/32": {
     "next-hops": {
     "next-hop": {
     "0": {
     "index": "0", 
     "config": {
     "next-hop": "192.168.0.1" }
     }, 
     "1": {
     "index": "1", 
     "config": {
     "next-hop": "10.0.0.1" }
     }
     }
     }, 
     "prefix": "192.0.2.1/32", 
     "config": {
     "set-tag": 42 }
     }
     }
     }
     }
    }

    注意,static 列表表示为JSON对象( 如果在别处加载了这里 JSON,则可以使用前缀引用前缀)。 obj["local-routes"]["static-routes"]["static"]["192.0.2.1/32"] )。

    也可以在类层次结构中serialise的子集,比如,只有一个 list 或者 container。 以下是( 到 ietf ):

    
    # Dump the static routes instance as JSON in IETF format
    
    
    print(pybindJSON.dumps(oclr.local_routes, mode="ietf"))
    
    
    
    

    和相应的输出:

    {
     "openconfig-local-routing:static-routes": {
     "static": [
     {
     "next-hops": {
     "next-hop": [
     {
     "index": "0", 
     "config": {
     "next-hop": "192.168.0.1" }
     }, 
     {
     "index": "1", 
     "config": {
     "next-hop": "10.0.0.1" }
     }
     ]
     }, 
     "prefix": "192.0.2.1/32", 
     "config": {
     "set-tag": 42 }
     }
     ]
     }
    }

    请注意,列表表示为一个 JSON array,按of规范表示,并且只有对象的static-routes 子级是 serialised。

    Deserialising数据实例

    PyangBind还支持从远程系统( 或者本地保存的文档) 获取数据实例,并将它的加载到新的或者现有的类集合中。 当远程系统发送一个数据实例响应查询时,程序员希望injest这样做。

    实例可以从任何支持的序列化格式( ( 请参见上方) ) 到类中都是 deserialised。

    要将serialise转换成新对象,可以使用serialise模块的load 方法:

    new_oclr = pybindJSON.load(os.path.join("json", "oc-lr.json"), binding, "openconfig_local_routing")

    这将创建 binding 模块中的openconfig_local_routing 类的新实例,并将来自 json/oc-lr.json的数据加载到它。 然后,可以按照任何其他类操作 new_oclr 对象:

    # Manipulate the data loadedprint("Current tag: %d"% new_oclr.local_routes.static_routes.static[u"192.0.2.1/32"].config.set_tag)# Outputs: 'Current tag: 42'new_oclr.local_routes.static_routes.static[u"192.0.2.1/32"].config.set_tag +=1print("New tag: %d"% new_oclr.local_routes.static_routes.static[u"192.0.2.1/32"].config.set_tag)# Outputs: 'Current tag: 43'

    同样,可以在现有的类集合中加载JSON实例- 这是通过直接调用相关的deserialisation类--来完成的,即 pybindJSONDecoder:

    # Load JSON into an existing class structurefrom pyangbind.lib.serialise import pybindJSONDecoderimport json
    ietf_json = json.load(open(os.path.join("json", "oc-lr_ietf.json"), 'r'))
    pybindJSONDecoder.load_ietf_json(ietf_json, None, None, obj=new_oclr.local_routes)

    直接 load_ietf_json 方法交付了JSON对象,不再需要模块和类名的参数,而是使用可选的参数指定与正在加载的JSON相对应的对象。

    在这里负载之后,可以遍历这些类,并在数据实例中显示原始加载的路由( 192.0.2.1/32 ) 和:文件( 192.0.2.2/32 ) 中

    # Iterate through the classes - both the 192.0.2.1/32 prefix and 192.0.2.2/32# prefix are now in the objectsfor prefix, route in new_oclr.local_routes.static_routes.static.iteritems():
     print("Prefix: {}, tag: {}".format(prefix, route.config.set_tag))# Output:# Prefix: 192.0.2.2/32, tag: 256# Prefix: 192.0.2.1/32, tag: 43

    示例代码

    这个工作示例可以在 docs/example/oc-local-routing 目录中找到。

    进一步的文档

    可以在 docs/ 目录--中找到关于PyangBind的实现和用法的进一步信息,其中提供了一个文档和示例容器列表,其中包含一个。

    许可证

    
    Copyright 2015, Rob Shakir (rjs@rob.sh)
    
    
    
    This project has been supported by:
    
    
     * Jive Communications, Inc.
    
    
     * BT plc.
    
    
    
    Licensed under the Apache License, Version 2.0 (the"License");
    
    
    you may not use this file except in compliance with the License.
    
    
    You may obtain a copy of the License at
    
    
    
     http://www.apache.org/licenses/LICENSE-2.0
    
    
    
    Unless required by applicable law or agreed to in writing, software
    
    
    distributed under the License is distributed on an"AS IS" BASIS,
    
    
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    
    
    See the License for the specific language governing permissions and
    
    
    limitations under the License.
    
    
    
    

    确认

    测试状态

    Build Status


    相关文章