背景
配置标准化其实是我们一直在探讨的事情,也是困扰很多网络运维管理人员的一大难题。
配置标准化,它包括两方面:
- 我们要刷的配置是符合制定的标准。
- 我们设备在线的配置应该是符合制定的标准的。
这其实是一个生成与解析的故事,我们今天就来讲讲配置的生成,配置的生成看似很简单的一个问题,我觉得坑却很多。
我们来讲讲两种情况,个人与团队:
个人:
我们很多工程师也都有自己的宝典,比如放到一个文件夹里,或者整齐或者凌乱,每次需要生成配置就摘出来一段以前的,然后改吧改吧,妥了,晚上变更刷就行了,这是很多网络工程师的一个工作思路。遇到细心点的,会在自己的宝典里备注一些规则,遇到什么样的问题,应该改改哪里。遇到熟悉的命令配置,可能查都不查,脑子里就可以浮现出来,然后写一行,加点UE或者Excel想办法生成很多行。
这种写出来的配置,完全是没有品控可言。甚至是非常非常危险的!
我以前晚上做变更就遇到过很多次:配置乍一看没问题,刷的时候就缺这少那。我想大家也应该深受其害!
团队:
我们意识到了需要管理配置,需要标准化,然后花大力气去写word文档,制作精良的用户手册,细细的描述配置生成的各种规则限制,然后再配置模板里把一些可变的参数用特殊的字符标记一下。非常详细的标准化手册,你按照上面的去写配置品控是有所进步的,理论上不会出错。但是这个很难坚持下来,总会有不去遵守配置标准文档自己写,或者看文档的时候走神、检查不仔细等等各种情况。因为人毕竟不是机器,总会有所懈怠。
事故发生,很多时候都是由于变更引起的,如果配置标准没有管理好,这对生产来说就是一个很大的隐患。
我们需要的是能长期坚持下去的配置生成标准化流程,解决这个问题的关键在于减少人的重复、枯燥、机械性的劳动,将运维人员聚焦到关键参数,其核心在于自动化,辅助以流程(比如多人复核):
在自动化部分,解决这个问题大体分两步:
将配置参数化、标准化,提取出程序可读的模板。
同时这也是一个持续的过程,我们一直讲NetDevOps具备成长属性个性化,我们的模板是基于自己的场景自己的规则,同时不断去丰富增多修改。没有一蹴而就的最佳实现,只有持续不懈的坚持与努力。
通过模板加参数批量自动生成配置,最好是基于模板引擎工具。
而今天我们也将介绍一款模板引擎工具 Jinja2(这是一个第三方包,请执行“pip install Jinja2”安装jinja2)
看完今天的分享,你会发现,原来配置生成标准化、自动化这么简单!
Jinja2
介绍
它的名字是日语神社的意思,去官网也是神社鸟居的一个logo。庙宇temple和模板template发音相近,所以起了这个名字。它是2.X的版本,所以包名是jinja2。官网说是兼容1.X。它最早是给web系统准备的,希望像JSP和PHP一样提供一种编程语言与模板系统的结合,基于Python,去实现web模板系统。是参考django(Python的一个web框架,后续会分享)的模板引擎去开发的,两者非常相似。
它有很多特点,可以很好的被运用在自动化领域:
1、它是基于plain text的模板引擎,可以非常方便的生成配置
2、易读,非常符合我们使用CLI的习惯
3、可扩展。我们可以编写自己的函数去拓展功能
4、灵活组合。可以继承调用另一个模板。
简单使用
安装
pip install Jinja2
python的包名和引入有时候有区别大家要注意。pip安装的时候对大小写是不敏感的,但是在引入包的时候一定要注意大小写。因为它底层会和路径有关联。
基本概念
Template:模板对象,从字符串加载成为一个模板对象。字符串是模板的内容,内含变量和控制循环等,由人去定义。
render:渲染函数,简单理解将模板中的变量填充值并执行其中的控制循环(可以无控制循环),得到一个字符串。
变与不变
模板引擎,我觉得要理解两个事情,变与不变。
变是值的变量、循环、控制、函数(过滤器、宏),会去让模板的输出发生变化。它是“引擎”,是动态的。
不变就是要输出的内容,是“模板”中静态的部分。
上面那个例子中,“Hello” 、空格、以及后面的叹号是要忠实输出的部分,name是一个变量,根据用户输入进行变化。
不变的部分好理解,那我们来说一下“变”
变量定义
变量定义是用两个花括号,前后空格,中间是变量名称或者是表达式。形如{{ variable }}。
支持的类型(同Python,在网络配置中经常用到的)有:字符串、数字、列表、字典、布尔。
我们可以根据实际需求配置去用这些数据类型,比如一系列的端口配置可以用字典的列表,每个字典是一个端口详细信息如上。我们接下来讲如何进行判断控制与循环。
循环和判断与Python基本一致但是
1、需要在外面用{%%}包裹起来,
2、用endif 或者endfor 来表明结束
3、不守缩进影响,Python讲究缩进,模板语言中没有留白,只要你愿意。
判断 if else
-%} 用来去掉这个符号后面紧邻它的空白符(空格、换行,一次去掉的个数无上限,有几个去几个)
上面的演示我们:
第一个:没有-% 且没换行,一行显示完全。
第二个:-%} 去掉了后面的空白符,如果有多个换行效果一样,它会去掉多个空白符。
第三个:没有-%} 所以保留了换行(即空白符)。
最后一定要有一个endif 不然会报错。因为无留白缩进,所以只能靠end来判断对应关系、层级结构。
我们在实际运用中,可以结合自己的配置,通过-%} 或者不使用来控制一些显示时的换行或者连接处无空白。
同时我们可以把模板放到文件中去,通过文件来加载模板,可以更易读,更容易调整。
Jinja有自己的加载文件的系统,我觉得大家还是在初期用最容易理解的方式来写就行,而且我们只是用来做配置生成,通过文件加载、读取字符串、创建Template对象是没有问题的,不涉及过多的web层面的安全问题。
循环 loop
我们用文件来加载模板,简单给端口做一个配置,并根据字段来判断是否启动端口。
我们先在同文件夹写一个interfaces.jinja文件。
config
{% for interface in interfaces %}
interface {{ interface.name }}
description {{ interface.description }}
{% if interface.up -%}
no shutdown
{% else-%}
shutdown
{% endif%}
{% endfor%}
commit
python代码
from jinja2 import Template
with open('interfaces.jinja','r',encoding='utf8') as f:
interfaces_temp = Template(f.read())
interfaces = [
{'name':'eth1/1', 'description':'connected to app01','up':True},
{'name':'eth1/2', 'description':'connected to app02','up':0},
]
interfaces_config = interfaces_temp.render(interfaces=interfaces)
print(interfaces_config)
结果:
interface eth1/1
config
interface eth1/1
description connected to app01
no shutdown
interface eth1/2
description connected to app02
shutdown
commit
注意:
我们用了-%} 去掉了判断条件所在的空白行,否则关端口和上面会有一个空行。
在Python的判断中,0、空字符串、False、空字典、空列表代表一个False。
我们可以把这个代码封装成一个函数(其实对象更好,对于初学者,我觉得先掌握函数即可)。
每次传入模板和变量,自动生成配置。
注释
jinja也支持注释,如果特别长的话是需要一点注释的。
注释的方法很简单。
{# … #} 用来进行注释,示例:
{# 这是一个端口配置的模板
args:
interfaces 字典的列表,形如:
[ {'name':'eth1/1', 'description':'connected to app01','up':True},
{'name':'eth1/2', 'description':'connected to app02','up':0}]
author :NetDevOps加油站
#}
config
{% for interface in interfaces %}
interface {{ interface.name }}
description {{ interface.description }}
{% if interface.up -%}
no shutdown
{% else -%}
shutdown
{% endif %}
{% endfor %}
commit
其他功能:
- jinja还支持模板的继承与导入
- 支持过滤器(简单理解是函数,写在Python文件里面,比如将字符串大写),支持自定义
- 支持宏(简单理解也是函数,但是必须在模板内声明)。让模板更简洁直观。复用代码。
初学者,掌握以上基本用法,就可以实现很多功能了。有想法的可以去看官方文档(英文版),2.11版本大约121页,很快就可以过一遍,大约1-2小时,有个大概了解。我们回头也会视情况分享一下高阶用法。
脑洞大开
- 我们讲完这些,大家其实还是可以和我们之前讲的内容结合自己的实际情况去串联。我开个脑洞,抛砖:
- 用netmiko从设备采集端口信息
- 正则解析出来,作为一些行为的依据,比如分配端口,结合端口状态、配置等信息得出结论(一个字段,表名是否可用此端口)
- 从端口列表,按需自动筛选出可用端口。
- 描述对端连接的设备、配置的VALN,或者其他配置(是access口还是其他口等等)
- 以上得到一些信息(分配的端口的,及配置),一份写入数据库或者表格作为备案。一份调用模板生成配置。
- 生成的配置按某种规则保存到文件中
- 利用文件将端口要变更的配置结合Netmiko推送到设备上去。
以后出配置我们还可以通过表格,表格里写一些参数,根据参数生成配置,甚至写一个web页面实现。甚至这些参数是从更高级别的业务参数去获取的,比如从云、从业务部门等等。
这也是我一直强调的运维人员聚焦到业务参数。
这个过程不是那么严谨,但是有很多很多点,我觉得都可以去细究、挖掘,希望给大家一些思路。毕竟NetDevOps一定要结合场景、自己的实际需求落地。
小结
今天分享了一点点,我对配置管理的初步理解,通过模板引擎结合程序,加一点点审核机制可以有效的避免以前配置生成的无法规范落地的窘境。有效的减少重复机械的劳动,充分调动起运维人员的经验,对于参数的把握,同时将运维经验固化。
希望大家能够喜欢~
非常希望能够给网络运维工程师分享一些实用的代码、思路、经验,也希望大家能够订阅、收藏、分享,给新人动力!
后续我也会继续为大家奉上干货——经验分享、代码实现、工具使用
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
前言 上一篇咱们介绍了 Hibernate 以及写了一个 Hibernate 的工具类,快速入门体验了一波 Hibernate 的使用,我们只需通过 Session 对象就能实现数据库的操作了。 现在,这篇介绍使用 Hibernate 进行基本的 CRUD、懒…