Ntc-templates 之前我们讲了谷歌的网络配置解析利器Textfsm,其优秀的设计思想,在核心代码1000行的情况下解决了网络配置解析的难题。

但这才是一个开始,我们需要基于Textfsm的规则去写大量的我们网络环境里的配置解析模板。这个过程是日积月累的一个过程,我们必须投入人力和时间。

作为textfsm的初学者,对于变化多端的网络配置,我们有什么办法”偷懒“吗?

答案是有的!

已经站在谷歌这位巨人的肩膀之上的我们,还可以百尺竿头更进一步——ntc-templates!

简介 ntc 是个什么东西? ntc意为 Network to Code。秉承了万物皆代码的思想,与infrastructure as code的思想相差无几,但是聚焦在了网络。

同时它是由networktocode( https://www.networktocode.com/)这个公司出品的,它们是做网络运维自动化的一个公司,在国外有一个知名的基于django的web 开源软件 Netbox,也是它们公司的产品。Netbox在国外常被作为Single Source of Truth,你可以简单与网络CMDB划等号。

ntc-templates是个什么东西 它是networktocode开源的一个产品。基于Textfsm规则做的,旨在聚集众多网络运维工程师的智慧,解决网络配置解析的难题。

Repository of TextFSM Templates for Network Devices, and Python wrapper for TextFSM's CliTable.

众多厂商网络设备的配置解析的TextFSM模板库 进一步封装Textfsm CliTable部分,可以非常简洁的使用进而解析出网络配置成结构化数据。 Ntc-templates的武器库 它内置了将近400个Textfsm解析模板,覆盖了国外主(思)流(科)的网络设备。思科占了很大一部分比重。同时也有国人贡献了很多H3C的相关命令的解析(华为的目前提交的不多,后续希望大家能贡献自己的模板,后续我也尝试提交一些自己的模板或者放到自己的github、gitee上)。

这些模板,拿来用完全没问题,但是有些细节需要调整,比如status有的会解析成down(Administrately down),它会把reason放解析到status里。(这个bug被解了只是举个例子)。

我们可能针对模板稍微修改,或者针对拿到的数据稍微修改,有时候二者结合,比如我们把解析的status up down对应到01等状态码。

接下来我们来看看它是如何使用的。 ** ntc-templates 使用** ntc-templates的安装 ntc-templates 的安装也比较简单,pip install ntc_templates即可 注意是下划线。

但是一个比较不幸的消息是:ntc-templates不能直接在windows下使用。但是安装不会报错,原因是ntc-templates调用了Textfsm的Clitable,但是CliTable中用了unix相关的接口。。。嗯,之前我们讲Textfsm也是聚焦在TextFsm的通用解析部分。

如果你是非windows可以跳过以下。

虚拟机、WSL(如果你是win10)、换电脑。

或者用我改写的parse.py去替代原来的,我将底层逻辑稍微修改,绕开了Clitable的调用,同时对模板的自动匹配用了自己的方法,也许有bug(原来的有一些锁机制),暂时没发现,我觉得执行效率比以前应该会有所提升。如果你担心别的,你也可以或者放到ntc-templates的安装后的路径底下,起一个别的名字。

像我这样。也可以直接替代parse.py(提前备份这个文件)。在调用的时候我们调用自己的parse即可,相关文件我会放到我的gitee上和github上。parse的核心代码只有48行,我去掉了注释应该比他少一些。如果大家是在linux、mac下开发,请无视我。

ntc-templates的思想 核心思想就是用网络设备平台与命令去匹配它所支持的模板库。设备平台比如cisco_nxos,命令比如是show int bri。它会去一个索引文件index(很重要,我们如果扩展也需要在这里写)查找匹配。

我们截取一段index


cisco_nxos_show_ip_ospf_database.textfsm, .*, cisco_nxos, sh[[ow]] ip o[[spf]] d[[atabase]]
cisco_nxos_show_ip_ospf_neighbor.textfsm, .*, cisco_nxos, sh[[ow]] ip ospf nei[[ghbor]]
cisco_nxos_show_interface_brief.textfsm, .*, cisco_nxos, sh[[ow]] int[[erface]] br[[ief]]

平台和命令之间会去掉空格,用下划线连接。命令支持一定程度的缩写。这个逻辑是Clitable里的。

然后就这样找到了textfsm模板。在同目录下是模板库,内置近400个模板。

它的核心价值在于众多模板。

Coding Time ntc-templates的使用及其简单,我们直接上代码吧

from ntc_templates.parse import parse_output

if __name__ == "__main__":
    with open('show_version.log', 'r', encoding='utf8') as f:
        raw_config_text = f.read()
    datas = parse_output(platform='cisco_nxos', command='show version', data=raw_config_text)
    print(datas)


    with open('show_int_bri.log', 'r', encoding='utf8') as f:
        raw_config_text = f.read()
    datas = parse_output(platform='cisco_nxos', command='show interface brief', data=raw_config_text)
    for i in datas:
        print(i)

读取文本文件或者从设备show后的字符串,赋值给data。platform输入对应的平台,可以参考netmiko支持的或者模板库。command赋上对应的命令即可。

调用ntc_templates.parse模块的parse_output函数即可。非常简单。

我们看看结果吧。

我们完全不需要写任何templates也可以使用。但是如果真正用到生产,可能需要对数据二次加工,比如up down状态是0 1,端口名称要全称等等细节。

网工界的TFBOYS——netmiko&textfsm&ntc-templates 刚才的用法我们是用文本解析的,有时候我们想实时登陆设备解析出来数据,按照传统思路是netmiko登设备,再调用上面的代码,写多了的话还是挺麻烦的。

于是乎netmiko整合了textfsm和ntc-templates,他们组成了NetDevOps世界里的TFBOYS。使用非常简单,在send_command的时候use_textfsm=True即可。


from netmiko import ConnectHandler

if __name__ == '__main__':
    dev_info = {
        'device_type': 'cisco_nxos',
        'ip': 'sbx-nxos-mgmt.cisco.com',
        'port': 8181,
        'username': 'admin',
        'password': 'XXX'
    }

    with ConnectHandler(**dev_info) as dev_connection:

        datas = dev_connection.send_command('show interface',use_textfsm=True)
        for data in datas:
            print(data)

看结果:

so easy!

但是这个地方有个坑,需要添加环境变量NET_TEXTFSM,指向你的templates目录,我们指向了ntc-templates的templates目录。

这个过程我们只是借用了ntc-templates的模板库,所以在win和linux下都能执行。因为netmiko内部自己去做了命令和模板的映射,避免了之前的不兼容问题。

对于三者使用的合与分,我觉得是按实际场景去进行的。大家在实际使用中去慢慢摸索吧!

脑洞大开 Ntc-templates可以很好的帮我解决数据的获取,以网工最熟悉的CLI方式,很香,我们基于ntc-templates其实可以梳理出很多信息,比如端口、软件版本,可以把这些数据集中统一存储,可以做巡检报告的数据源、可以定制一些SNMP无法采集的监控指标,出配置的依据,故障应急时的检查项等等。网络运维自动化的重点应该是数据,所有的内容都是围绕数据展开,从采集数据到数据的使用,形成一个合理的闭环,内驱的闭环,尽量少人为干预的闭环。

最后奉上我的parse.py代码。ntc-templates路径大家可以用pip show ntc-templates即可看到路径,找到对应文件夹后替换对应文件,大家也可以改写一其中的_get_template_dir函数,从环境变量里读取tempaltes的路径。


"""ntc_templates.parse."""
import os
from textfsm import TextFSM
import re


def _get_template_dir():
    # 大家也可以把templates拷贝到指定目录,在这个函数里通过环境变量读取路径。后续可以自己维护自己的templates
    package_dir = os.path.dirname(__file__)
    template_dir = os.path.join(package_dir, "templates")
    if not os.path.isdir(template_dir):
        project_dir = os.path.dirname(os.path.dirname(os.path.dirname(template_dir)))
        template_dir = os.path.join(project_dir, "templates")

    return template_dir


def get_textfsm_obj(Command, Platform):
    '''
    通过设备的平台和cmd去匹配index中对应的模板
    不调用处理table,从而完成对windows的彻底兼容
    但也对文件锁等细节处理不当,但是在个人PC上演示调试不会造成太大问题。
    '''
    Command_re_str = ' '.join(['{}{}'.format(i, '[a-zA-Z0-9]*?') for i in Command.split()])
    re_str = r'.*?{}.*? .*?{}.*?'.format(Platform, Command_re_str)
    re_str = re_str.replace(' ', '_').lower()
    textfsm_templ_re = re.compile(re_str)
    index_file = os.path.join(_get_template_dir(), 'index')
    with open(index_file, 'r', encoding='utf8') as f:
        index_text = f.read()
    result = textfsm_templ_re.search(index_text)
    if result:
        textfsm_templ_name = '{}.textfsm'.format(result.group())
    else:
        raise Exception('No template found for attributes: "%s"' %
                        attributes)
    textfsm_templ_iofile = open(os.path.join(_get_template_dir(), textfsm_templ_name), 'r', encoding='utf8')
    return TextFSM(textfsm_templ_iofile)


def parse_output(platform=None, command=None, data=None):
    """Return the structured data based on the output from a network device."""

    attrs = {"Command": command, "Platform": platform}
    fsm = get_textfsm_obj(**attrs)
    structured_data = fsm.ParseTextToDicts(data)
    structured_data_lower = []
    structured_data_lower = [{k.lower(): v for k, v in data.items()} for data in structured_data]
    # for data in structured_data:
    #     structured_data_lower.append(
    #         {k.lower():v for k,v in data.items()}
    #     )
    return structured_data_lower

gitee地址:

https://gitee.com/feifeiflight/NetDevOpsShare/tree/master/codes/ntc_templates_codes

最后欢迎大家点赞、喜欢、在读、分享、收藏等等。

NetDevOps加油站,同名公众号与知乎专栏,欢迎大家一同关注!