博科光纤交换机端口别名映射脚本

时间:2024-04-16 13:36:08

登录交换机使用 switchshow 查看不同端口的port 类型

操作步骤:

  1. 将fc_discovery.py脚本放在监控服务器的externalscript目录,并执行以下命令,增加脚本可执行权限:chmod 755 fc_discovery.py
  2. 将fc_reflect_dependence.tar.gz传到监控服务器上,解压到新建目录中,执行以下命令安装: pip install ./*,安装有问题的话需要按依赖关系分别安装
  3. 在FC模板页面,自动发现中“PORT Discovery”的键值按如下格式调整:类型:外部检查 键值:fc_discovery.py["-u","admin","-p","password","-i","10.11.11.11","-c","public"]
  4. 在监控项原型中,把每个监控项原型中的监控项名称中[{#SFP_NAME}]替换为{#SFP_NAME}
  5. 在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())
        }))