H3C 防火墙(v7)提取导出安全策略至表格(textfsm)

This is an article that was created 421 days ago, and the information may have evolved or changed.

去年写过一版这个需求的python代码,使用的是if判断语句进行匹配获取内容然后写入表格

H3C 防火墙(v7)提取导出安全策略至表格

当时主打一个使用最少的库,最易理解和最长代码原则(哈哈),现在改用textfsm来实现这个需求

测试环境

  • Microsoft Windows 10 Pro 21H2
  • Visual studio code Update 1.77.3
  • Python 3.10.10
  • HCL 5.7.2
  • DeviceModel:H3C SecPath F1090

安装的库

使用 pip 安装 openpyxl ,pandas ,wcwidth,ntc-templates-elinpf,其他库为第三方库安装时自动安装的依赖(除pip和setuptools外)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Package              Version
-------------------- -------
et-xmlfile 1.1.0
future 0.18.3
ntc-templates-elinpf 3.6.1
numpy 1.24.3
openpyxl 3.1.2
pandas 1.5.3
pip 23.1.2
python-dateutil 2.8.2
pytz 2023.3
setuptools 65.5.0
six 1.16.0
textfsm 1.1.3
tzdata 2023.3
wcwidth 0.2.6

textfsm模板

编写三个textfsm模板文件,分别处理以下命令的回显内容

1
2
3
4
5
6
# 查看安全策略
dis security-policy ip
# 查看地址对象组
dis object-group ip address
# 查看服务对象组
dis object-group service

hp_comware_display_security-policy_ip_local.textfsm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Value Required RULE_ID (\d+)
Value RULE_NAME (\S+(?:\s\S+)*)
Value ACTIVE_STATE (Inactive|Active)
Value ACTION (pass|drop)
Value VRF (\S+(?:\s\S+)*)
Value PROFILE (\S+(?:\s\S+)*)
Value LOGGING (enable|disable)
Value List COUNTING (\S+(?:\s\S+)*)
Value TIME_RANGE (\S+(?:\s\S+)*)
Value DESC (\S+(?:\s\S+)*)
Value List SESSION (\S+(?:\s\S+)*)
Value List SRC_ZONE (\S+(?:\s\S+)*)
Value List DEST_ZONE (\S+(?:\s\S+)*)
Value List SRC_IP (\S+(?:\s\S+)*)
Value List DEST_IP (\S+(?:\s\S+)*)
Value List SERVICE (\S+(?:\s\S+)*)
Value List APPLICATION (\S+(?:\s\S+)*)
Value List USER (\S+(?:\s\S+)*)

Start
^\s+rule \d+ name \S+ -> Continue
^\s+rule ${RULE_ID} name ${RULE_NAME} -> Continue
^\s+rule ${RULE_ID} name ${RULE_NAME} \(${ACTIVE_STATE}\)
^\s+action ${ACTION}
^\s+vrf ${VRF}
^\s+profile ${PROFILE}
^\s+logging ${LOGGING}
^\s+counting ${COUNTING}
^\s+time-range ${TIME_RANGE}
^\s+description ${DESC}
^\s+session ${SESSION}
^\s+source-zone ${SRC_ZONE}
^\s+destination-zone ${DEST_ZONE}
^\s+source-ip ${SRC_IP}
^\s+source-ip\S+ ${SRC_IP}
^\s+destination-ip ${DEST_IP}
^\s+destination-ip\S+ ${DEST_IP}
^\s+service ${SERVICE}
^\s+service-port ${SERVICE}
^\s+application ${APPLICATION}
^\s+user ${USER}
^\s+source-mac ${SRC_IP}
^$$ -> Record

hp_comware_display_object-group_ip_local.textfsm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Value Required OBJ_GROUP_NAME (\S+(?:\s\S+)*)
Value List OBJ_ITEM (\S+(?:\s\S+)*)
Value REFERENCED (in use|out of use)
Value SEC_ZONE (\S+(?:\s\S+)*)
Value DESC (\S+(?:\s\S+)*)

Start
^Ip address object group -> Continue
^Ip address object group ${OBJ_GROUP_NAME}: \d+ objects\(${REFERENCED}\)
^security-zone ${SEC_ZONE}
^< -> NoRecord
^${DESC}
^\s+object -> NoRecord
^\s+${OBJ_ITEM}
^$$ -> Record

hp_comware_display_object-group_service_local.textfsm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Value Required OBJ_GROUP_NAME (\S+(?:\s\S+)*)
Value List OBJ_ITEM (\S+(?:\s\S+)*)
Value REFERENCED (in use|out of use)
Value DESC (\S+(?:\s\S+)*)

Start
^Service object group -> Continue
^Service object group ${OBJ_GROUP_NAME}: \d+ objects\(${REFERENCED}\)
^< -> NoRecord
^${DESC}
^\s+object -> NoRecord
^\s+${OBJ_ITEM}
^$$ -> Record

python脚本

原理是使用textfsm模板对三个命令的回显内容进行处理然后写入表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
from textfsm import TextFSM
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import PatternFill
import openpyxl
from datetime import datetime
import wcwidth


class SP2EXCEL:

# 初始化一些内容
def __init__(self, echo_content):
self.sp_textfsm_path = 'hp_comware_display_security-policy_ip_local.textfsm'
self.obj_ip_textfsm_path = 'hp_comware_display_object-group_ip_local.textfsm'
self.obj_service_textfsm_path = 'hp_comware_display_object-group_service_local.textfsm'

# 回显内容读入内存
with open(echo_content, 'r', encoding='utf8') as f:
self.contents = f.read()


# 0、字典的value是列表的,将列表拼接为一个以换行符为分隔符的字符串
def expand_list(self, list_dict_res):
for d in list_dict_res:
for k, v in d.copy().items():
if isinstance(v, list):
# 将列表拼接为一个以换行符为分隔符的字符串
obj_item_str = '\n'.join(v)
# 写回原字典
d[k] = obj_item_str

return list_dict_res


# 1、解析 dis security-policy ip 回显内容(安全策略)
def parse_sp(self):

with open(self.sp_textfsm_path, encoding='utf8') as f:
template = TextFSM(f)
res = template.ParseTextToDicts(self.contents)

# 对没有匹配到内容的设置默认值
for d in res:
if d['ACTIVE_STATE'] == '':
d['ACTIVE_STATE'] = 'Active'
if d['VRF'] == '':
d['VRF'] = 'public'
if d['PROFILE'] == '':
d['PROFILE'] = 'none'
if d['LOGGING'] == '':
d['LOGGING'] = 'disable'
if not d['COUNTING']:
d['COUNTING'] = 'disable'
if d['TIME_RANGE'] == '':
d['TIME_RANGE'] = 'none'
if d['DESC'] == '':
d['DESC'] = 'none'
if not d['SESSION']:
d['SESSION'] = 'none'
if not d['SRC_ZONE']:
d['SRC_ZONE'] = 'any'
if not d['DEST_ZONE']:
d['DEST_ZONE'] = 'any'
if not d['SRC_IP']:
d['SRC_IP'] = 'any'
if not d['DEST_IP']:
d['DEST_IP'] = 'any'
if not d['SERVICE']:
d['SERVICE'] = 'any'
if not d['APPLICATION']:
d['APPLICATION'] = 'any'
if not d['USER']:
d['USER'] = 'any'

# 调用expand_list()处理字典value为列表的键值对
res = self.expand_list(res)

df = pd.DataFrame(res)

# 安全策略表头
df_th = {'RULE_ID': 'ID', 'RULE_NAME': '名称', 'ACTIVE_STATE': '时间段状态', 'ACTION': '动作', 'VRF': '公网', 'PROFILE': '内容安全', 'LOGGING': '日志', 'COUNTING': '统计', 'TIME_RANGE': '时间段', 'DESC': '描述', 'SESSION': '会话', 'SRC_ZONE': '源安全域', 'DEST_ZONE': '目的安全域', 'SRC_IP': '源地址', 'DEST_IP': '目的地址', 'SERVICE': '服务', 'APPLICATION': '应用', 'USER': '用户'}

self.sp_df = df.rename(columns=df_th)

# 下一步进行解析地址对象组回显内容
self.parse_obj_ip()


# 2、解析 dis object-group ip address 回显内容(地址对象组)
def parse_obj_ip(self):

with open(self.obj_ip_textfsm_path, encoding='utf8') as f:
template = TextFSM(f)
res = template.ParseTextToDicts(self.contents)

# 调用expand_list()处理字典value为列表的键值对
res = self.expand_list(res)

df = pd.DataFrame(res)

# 地址对象组表头
df_th = {'OBJ_GROUP_NAME': '对象组名称', 'OBJ_ITEM': '对象', 'REFERENCED': '被引用', 'SEC_ZONE': '安全域', 'DESC': '描述'}
self.obj_ip_df = df.rename(columns=df_th)

# 下一步进行解析服务对象组回显内容
self.parse_obj_service()

# 3、解析 dis object-group service 回显内容(服务对象组)
def parse_obj_service(self):

with open(self.obj_service_textfsm_path, encoding='utf8') as f:
template = TextFSM(f)
res = template.ParseTextToDicts(self.contents)

# 调用expand_list()处理字典value为列表的键值对
res = self.expand_list(res)

df = pd.DataFrame(res)

# 服务对象组表头
df_th = {'OBJ_GROUP_NAME': '对象组名称', 'OBJ_ITEM': '对象', 'REFERENCED': '被引用', 'DESC': '描述'}
self.obj_service_df = df.rename(columns=df_th)


# 4、表格写入
def to_excel(self):

# 运行以上三个解析内容的函数,一个串一个
self.parse_sp()

# 文件名时间部分,用于区别新旧
create_time = datetime.now().strftime("%Y%m%d%H%M%S")
self.output_path = f'核心防火墙安全策略统计{create_time}.xlsx'

# 创建ExcelWriter对象并指定文件名
with pd.ExcelWriter(self.output_path) as writer:
# 将三个DataFrame写入不同的工作表中,并且不写入行索引
self.sp_df.to_excel(writer, sheet_name='安全策略', index=False)
self.obj_ip_df.to_excel(writer, sheet_name='地址对象组', index=False)
self.obj_service_df.to_excel(writer, sheet_name='服务对象组', index=False)

# 取出wb对象供define_excel_style()使用
self.wb = writer.book
self.sheet_names = self.wb.sheetnames

self.define_excel_style()


# 5、调整表格样式
def define_excel_style(self):

# 三个sheet
self.ws1 = self.wb[self.sheet_names[0]]
self.ws2 = self.wb[self.sheet_names[1]]
self.ws3 = self.wb[self.sheet_names[2]]

# 以单元格中当行最长字符串长度调整列宽
for sheet_name in self.sheet_names:
worksheet = self.wb[sheet_name]
# 遍历所有列,找出最宽的一列并调整列宽
for col in worksheet.columns:
max_width = 0
column = col[0].column # openpyxl 中的列索引从 1 开始

# 计算每个单元格中最宽行的显示宽度,并选取最宽的一行
for cell in col:
lines = str(cell.value).split("\n")
max_line_width = 0
for line in lines:
width = wcwidth.wcswidth(line) + 2
if width > max_line_width:
max_line_width = width
if max_line_width > max_width:
max_width = max_line_width

# 将最宽行的显示宽度设置为该列的列宽
worksheet.column_dimensions[openpyxl.utils.get_column_letter(column)].width = max_width

# 冻结首行
self.ws1.freeze_panes = 'A2'
self.ws2.freeze_panes = 'A2'
self.ws3.freeze_panes = 'A2'

# 表头背景色
th_color_fill = PatternFill('solid', fgColor='D3D3D3')
for col in range(1, 19):
self.ws1.cell(row=1, column=col).fill = th_color_fill
for col in range(1, 6):
self.ws2.cell(row=1, column=col).fill = th_color_fill
for col in range(1, 6):
self.ws3.cell(row=1, column=col).fill = th_color_fill

# 垂直居中
for sheet_name in self.sheet_names:
worksheet = self.wb[sheet_name]
for r in worksheet:
for c in r:
c.alignment = openpyxl.styles.Alignment(vertical='center',
wrapText=True)

# 保存
self.wb.save(self.output_path)


if __name__ == '__main__':

# 指定回显输出文件路径,同目录下直接 文件名
echo_content_path = 'output.log'
# 实例化对象
obj = SP2EXCEL(echo_content_path)
# 执行 4、表格写入
obj.to_excel()

print('搞快点-->>搞快点-->>')

生成的表格文件

安全策略sheet

ScreenCaputure230510175500

地址对象组sheet

ScreenCaputure230510175522

服务对象组sheet

ScreenCaputure230510180429

image-20230510181500219

最后

添加hexo文章时效性提示 BLOG CHANGELOG
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×