博科光纤交换机端口别名映射脚本
登录交换机使用 switchshow 查看不同端口的port 类型
操作步骤:
- 将fc_discovery.py脚本放在监控服务器的externalscript目录,并执行以下命令,增加脚本可执行权限:chmod 755 fc_discovery.py
- 将fc_reflect_dependence.tar.gz传到监控服务器上,解压到新建目录中,执行以下命令安装: pip install ./*,安装有问题的话需要按依赖关系分别安装
- 在FC模板页面,自动发现中“PORT Discovery”的键值按如下格式调整:类型:外部检查 键值:fc_discovery.py["-u","admin","-p","password","-i","10.11.11.11","-c","public"]
- 在监控项原型中,把每个监控项原型中的监控项名称中[{#SFP_NAME}]替换为{#SFP_NAME}
- 在server上定义一个crontab,每天执行一个这个脚本,脚本每天会生成一个对应ip的别名文件,有文件的情况下自动发现规则去执行的时候是去读文件,获取文件内的数据返回,没有文件的话会去执行一次脚本生成文件,但是返回数据的时候有超时的问题。
#!/bin/python
# coding: utf-8
# Py2.7
import argparse
import json
import os
import re
import datetime
from fabric import Connection
# 博科光纤交换机的端口oid
SFP_NAME_OID = "1.3.6.1.4.1.1588.2.1.1.1.6.2.1.37"
def execute_cmd(conn, cmd):
with conn as c:
rs = c.run(cmd, hide=True) # fabric执行命令,hide屏蔽执行命令的默认输出。
return rs.stdout
def get_snmp_data(ip, community='public'):
rtn = {}
# snmpwalk获取对应oid的值,对值进行正则匹配,该OID可能有STRING INTEGER两种类型,酌情使用
# patterns = re.compile('^.*\.(\d+)\s=\sINTEGER:\s.*(\d+).*$')
patterns = re.compile('^.*\.(\d+)\s=\sSTRING:\s.*\"(\d+)\".*$')
ret = os.popen('snmpwalk -v2c -c %s %s %s' % (community, ip, SFP_NAME_OID))
for r in ret.readlines():
m = patterns.match(r)
rtn[m.group(1)] = {
'{#SFP_NAME}': m.group(2),
'{#SNMPINDEX}': m.group(1),
'{#SFP_ALIAS}':''
}
return rtn
# 查找 F-Port类型的别名
def get_alias(conn, target):
cmd = 'nodefind %s' % target
res = execute_cmd(conn, cmd=cmd)
for r in res.splitlines()[-1:]:
m = re.match('.*Aliases:\s*(.*)\s*.*$', r)
if m:
return m.group(1)
return ''
# 在交换机上执行命令,查看各个端口的Port类型,根据不同类型获取各自的别名。
def get_switchshow(conn, rtn):
res = execute_cmd(conn, cmd='switchshow')
for r in res.splitlines():
s = r.strip().split()
if len(s) < 9:
continue
try:
# F-Port的情况不能直接获取到别名信息需要调用下一个命令 nodefind,使用8位置参数去发现别名
if s[7] == 'F-Port':
target = s[8]
rtn[s[1]]['{#SFP_ALIAS}'] = get_alias(conn, target)
# E-Port有两种情况,位置可能处于7活着8,在switchshow的返回数据中就可以获取到别名,分别是9,10位置的值
elif s[7] == 'E-Port':
rtn[s[1]]['{#SFP_ALIAS}'] = s[9]
elif s[8] == 'E-Port':
rtn[s[1]]['{#SFP_ALIAS}'] = s[10]
except Exception as e:
continue
return rtn
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--port", "-P", action="store", help="port", required=False, default=22)
parser.add_argument("--ip", "-i", action="store", help="ip", required=True)
parser.add_argument("--user", "-u", action="store", help="user", required=True)
parser.add_argument("--password", "-p", action="store", help="password", required=True)
parser.add_argument("--name", "-n", action="store", help="name", required=False, default='all')
parser.add_argument("--community", "-c", action="store", help="community", required=False, default='public')
args = parser.parse_args()
path = '/usr/local/sdata/fc_data/{}_{}.txt'.format(args.ip,datetime.datetime.now().strftime("%Y%m%d"))
# 判断文件,有文件就读文件,返回其中的数据
if os.path.isfile(path):
with open(path, 'r') as rf:
data = rf.read()
print(data)
# 没有文件的话,就会链接交换机,去获取数据 ,并生成文件,供下次使用
else:
conn = Connection(host=args.ip, port=args.port, user=args.user, connect_kwargs={"password": args.password})
rtn = get_snmp_data(args.ip, args.community)
rtn = get_switchshow(conn, rtn)
with open(path, 'w') as f:
f.write(json.dumps({'data': list(rtn.values())}))
print(json.dumps({
'data': list(rtn.values())
}))