2019-05-09-2

def queryCpuStatus(host, passwd, oid):
""" 查询监控对象CPU使用率"""
try:
result = getSNMPResult(host, passwd, oid)
if result is None:
return

    used = 0.00
    lines = result.split('\n')
    for idx, line in enumerate(lines):
        match = re.search(r'INTEGER:\s+(\d+)', line)
        if match:
            used += float(match.group(1))
    if idx:
        cpu_used = used / idx
except Exception:
    errMsg("get cpu used rate failed!")
else:
    # debugMsg("CPU USED:{0}".format(cpu_used))
    return cpu_used

def queryMemStatus(host, passwd, oid):
"""查询监控对象内存使用率"""
# step 1: get physical memory offset num
if "par_type" not in oid:
result = getSNMPResult(host, passwd, oid, r"INTEGER:\s+(\d+)")
if result:
mem_used = int(result.group(1))
else:
# 初始值
total_size, cu_size, cu_num = 0, 0, 0

    result = getSNMPResult(host, passwd, oid["par_type"])
    if result is None:
        return

    lines = result.split('\n')
    physic_mem_id = ''
    for line in lines:
        match = re.search(r"\.(\d+)\s+=\s+STRING:\s+(P|p)hysical (M|m)emory", line)
        if match:
            physic_mem_id = match.group(1)
            break

    # step 2: get single cu size
    if not physic_mem_id:
        return

    result = getSNMPResult(host, passwd, oid["cu_size"])
    if result is None:
        return

    lines = result.split('\n')
    for line in lines:
        match = re.search(r'\.(\d+)\s+=\s+INTEGER:\s+(\d+)', line)
        if match and match.group(1) == physic_mem_id:
            cu_size = int(match.group(2))
            break

    # step 3: get the number of cu:
    result = getSNMPResult(host, passwd, oid["cu_num"])
    if result is None:
        return

    lines = result.split('\n')
    for line in lines:
        match = re.search(r'\.(\d+)\s+=\s+INTEGER:\s+(\d+)', line)
        if match and match.group(1) == physic_mem_id:
            cu_num = int(match.group(2))
            break

    # step 4:get total size
    result = getSNMPResult(host, passwd, oid["total_size"], r'INTEGER:\s+(\d+)')
    if result is None:
        return

    total_size = int(result.group(1))
    if total_size > 0:
        mem_used = (cu_num * cu_size)/1024.0/total_size * 100.0

# debugMsg("MEM USED:{0}".format(mem_used))
return mem_used 

def queryDiskStatus(host, passwd, oid):
"""查询监控对象硬盘使用率"""
disk_used = {}
if "disk_info" not in oid:
result = getSNMPResult(host, passwd, oid["total_size"], r"INTEGER:\s+(\d+)")
if result is None:
return

    total_size = float(result.group(1))
    result = getSNMPResult(host, passwd, oid["valid_size"], r"INTEGER:\s+(\d+)")        
    if result is None:
        return

    valid_size = float(result.group(1))
    if total_size > 0:
        disk_used["disk"] = (total_size - valid_size) / total_size * 100.0
else:
    disk_info = defaultdict(lambda : dict(name="", cu_num=0, used_num=0))

    result = getSNMPResult(host, passwd, oid["disk_info"])
    if result is None:
        return
    lines = result.split('\n')
    for line in lines:
        # consider whether remove it??
        #if '\\' in line or '/' in line:
        # 不显示Memory buffers、Physical memory等
        match = re.search(r"\.(\d+)\s+=\s+STRING:\s+([ \w\d\/\_\-\\\:]+)", line)
        if match:
            disk_info[match.group(1)]["name"] = match.group(2)

    result = getSNMPResult(host, passwd, oid["cu_num"])
    if result is None:
        return

    lines = result.split('\n')
    for line in lines:
        match = re.search(r"\.(\d+)\s+=\s+INTEGER:\s+(\d+)", line)
        if match:
            disk_info[match.group(1)]["cu_num"] = int(match.group(2))

    result = getSNMPResult(host, passwd, oid["used_num"])
    if result is None:
        return

    lines = result.split('\n')
    for line in lines:
        match = re.search(r"\.(\d+)\s+=\s+INTEGER:\s+(\d+)", line)
        if match:
            disk_info[match.group(1)]["used_num"] = float(match.group(2))

    for entry in disk_info.values():
        if entry["cu_num"] > 0:
            disk_used[entry["name"]] = u'%.2f' % (entry["used_num"] / entry["cu_num"] * 100)
        else:
            disk_used[entry["name"]] = u'0.00'

disks = []
for k, v in disk_used.items():
    disks.append(u"%s:%s" % (k,v))

return disks

def queryIfacesDesc(host, passwd, oid):
"""
网络接口信息描述
包括网络接口名称,以及后续需要的接口编号
"""
default_entry = {
"name": u"暂无",
"status_info": u"", # 接口状态
"ip_info": u"", # 接口ip地址
"mac_info": u"", # 接口mac地址
"out": 0,
"out_err": 0, # 发送错误
"out_ucast": 0,
"out_nucast": 0,
"out_discards": 0,
"in": 0,
"in_err": 0,
"in_ucast": 0,
"in_nucast": 0,
"in_discards": 0
}
ifaces_table = defaultdict(lambda: dict(default_entry))
result = getSNMPResult(host, passwd, oid)
if result is None:
return

lines = result.split('\n')
for line in lines:
    match = re.search(r"\.(\d+)\s+=\s+STRING:\s+(.*)", line)
    if match is not None:
        try:
            iface_name = match.group(2)
            detect_result = chardet.detect(iface_name)
            if detect_result and detect_result['encoding'] is not None:
                iface_name = iface_name.decode(detect_result['encoding'])
        except Exception:
            errMsg("queryIfacesDesc failed!")
            iface_name = u"暂无"
        finally:
            ifaces_table[match.group(1)]["name"] = iface_name

return ifaces_table

def queryIfaceStatus(host, passwd, oid):
"""查询监控对象网络接口状态"""
ifaces_table = queryIfacesDesc(host, passwd, oid["desc_info"])
if ifaces_table is None:
return None, None

# 获取网络接口当前操作状态(up/down)
result = getSNMPResult(host, passwd, oid["status_info"])
if result is None:
    return None, None

lines = result.split('\n')
for line in lines:
    # IF-MIB::ifOperStatus.1 = INTEGER: up(1)
    # 分组1: 编号 分组2: 接口状态 分组3: 状态码(1/2/3)
    match = re.search(r"\.(\d+)\s+=\s+INTEGER:\s+(\w+)\((\d+)\)", line)
    if match:
        status = match.group(3)
        if_entry_id = match.group(1)
        
        status_str = {"1": "up", "2": "down", "3": "test", "6": "x"}.get(status)
        if status_str is None:
            ifaces_table[if_entry_id]["status_info"] = match.group(2)
        elif status_str == "x":
            if if_entry_id in ifaces_table: del ifaces_table[if_entry_id]
        else:
            ifaces_table[if_entry_id]["status_info"] = status_str

# 获取接口的ip地址
result = getSNMPResult(host, passwd, oid["ip_info"])
lines = result.split('\n')
for line in lines:
    # IP-MIB::ipAdEntIfIndex.127.0.0.1 = INTEGER: 1
    # 分组1: 接口ip地址 分组2: 接口编号
    match = re.search(r"\.([\w\d\.]+)\s+=\s+INTEGER:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(2)
        ifaces_table[if_entry_id]["ip_info"] = match.group(1) or u""

# 获取接口的mac地址
result = getSNMPResult(host, passwd, oid["mac_info"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifPhysAddress.2 = STRING: 28:51:32:8:cb:32
    # 分组1: 接口编号 分组2: 接口mac地址(该分组可能为空)
    match = re.search(r"\.(\d+)\s+=\s+STRING:\s+([\w\:\d]+)?", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["mac_info"] = match.group(2) or u""

# 获取接口发送错误的包个数
"""The number of outbound packets that could not be
transmitted because of errors."""
result = getSNMPResult(host, passwd, oid["out_err"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifOutErrors.1 = Counter32: 0
    # 分组1: 接口编号 分组2: 包个数
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["out_err"] = int(match.group(2))

# 获取接口已发送的包个数(单播, 包括丢弃和错误的)
"""
The total number of packets that higher-level
protocols requested be transmitted to a
subnetwork-unicast address, including those that
were discarded or not sent.
"""
result = getSNMPResult(host, passwd, oid["out_ucast"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifOutUcastPkts.1 = Counter32: 1965
    # 分组1: 接口编号 分组2: 包个数
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["out_ucast"] = int(match.group(2))

# 发送丢包数
"""
The number of outbound packets which were chosen
to be discarded even though no errors had been
detected to prevent their being transmitted.  One
possible reason for discarding such a packet could
be to free up buffer space.
"""
result = getSNMPResult(host, passwd, oid["out_discards"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifOutDiscards.1 = Counter32: 0
    # 分组1: 接口编号 分组2: 包个数
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["out_discards"] = int(match.group(2))

# 获取接口已发送总包数(非单播,包括丢弃和错误的)
"""
The total number of packets that higher-level
protocols requested be transmitted to a non-
unicast (i.e., a subnetwork-broadcast or
subnetwork-multicast) address, including those
that were discarded or not sent.
"""
result = getSNMPResult(host, passwd, oid["out_nucast"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifOutNUcastPkts.1 = Counter32: 0
    # 分组1: 接口编号 分组2: 包个数
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["out_nucast"] = int(match.group(2))

# 获取接口已接收错误的包个数
"""The number of inbound packets that contained
errors preventing them from being deliverable to a
higher-layer protocol."""
result = getSNMPResult(host, passwd, oid["in_err"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifOutErrors.1 = Counter32: 0
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["in_err"] = int(match.group(2))

# 获取接口已接收的总包数(非单播)
"""
The number of non-unicast (i.e., subnetwork-
broadcast or subnetwork-multicast) packets
delivered to a higher-layer protocol.
"""
result = getSNMPResult(host, passwd, oid["in_nucast"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifInNUcastPkts.2 = Counter32: 326439
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["in_nucast"] = int(match.group(2))

# 获取接口已接收的总包数(单播)
"""The number of subnetwork-unicast packets
delivered to a higher-layer protocol."""
result = getSNMPResult(host, passwd, oid["in_ucast"])
lines = result.split('\n')
for line in lines:
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["in_ucast"] = int(match.group(2))

# 接收的丢包数
"""
The number of inbound packets which were chosen
to be discarded even though no errors had been
detected to prevent their being deliverable to a
higher-layer protocol.  One possible reason for
discarding such a packet could be to free up
buffer space.
"""
result = getSNMPResult(host, passwd, oid["in_discards"])
lines = result.split('\n')
for line in lines:
    # IF-MIB::ifInDiscards.1 = Counter32: 0
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["in_discards"] = int(match.group(2))

# 接口接收的总字节数
"""The total number of octets received on the
interface, including framing characters."""
result = getSNMPResult(host, passwd, oid["in"])
lines = result.split('\n')
for line in lines:
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["in"] = int(match.group(2))

# 接口发送的总字节数
"""
The total number of octets transmitted out of the
interface, including framing characters."""
result = getSNMPResult(host, passwd, oid["out"])
lines = result.split('\n')
for line in lines:
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["out"] = int(match.group(2))

result = getSNMPResult(host, passwd, oid["sys_time"], r"Timeticks:\s+\((\d+)\)")    
start_time = int(result.group(1))
time.sleep(10)

# 计算单位时间内接收总数和发送总数
result = getSNMPResult(host, passwd, oid["in"])
lines = result.split('\n')
for line in lines:
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["in"] = int(match.group(2)) - ifaces_table[if_entry_id]["in"]

result = getSNMPResult(host, passwd, oid["out"])
lines = result.split('\n')
for line in lines:
    match = re.search(r"\.(\d+)\s+=\s+Counter32:\s+(\d+)", line)
    if match:
        if_entry_id = match.group(1)
        ifaces_table[if_entry_id]["out"] = int(match.group(2)) - ifaces_table[if_entry_id]["out"]

result = getSNMPResult(host, passwd, oid["sys_time"], r"Timeticks:\s+\((\d+)\)")
end_time = int(result.group(1))    
stamp_time = end_time - start_time

return ifaces_table, stamp_time

def snmpDetected(monitor_info, params):
"""
描述:
监控对象基本运行状态检测
参数:
:params:
:object_id: 监控对象id
:hosts: 监控对象ip地址
:group_name: 监控对象所属组(用于获取信息oid)
:passwd: 团体字符串
{"object_id": "x", "hosts": ["x", "y"],
"group_name": "x", "passwd": "x"}
返回:
返回一个str, 监控状态记录
"""
hosts = params["hosts"]
monitor_id = params["object_id"]
group_name = params["group_name"]
if group_name not in monitor_info:
return None

passwd = "public" if not params["passwd"] else params["passwd"]

# 检测时间
check_time = getCurrentTime()

oids = monitor_info[group_name]
results = []
for host in hosts:
    cpu_used = queryCpuStatus(host, passwd, oids["cpu"])
    mem_used = queryMemStatus(host, passwd, oids["mem"])    
    disks = queryDiskStatus(host, passwd, oids["disk"])
    if cpu_used and mem_used and disks:
        results.append(MONITE_FORMAT_N % (check_time, monitor_id,
                                         host, cpu_used, mem_used,
                                         ','.join(disks)))

    ifaces_table, stamp_time = queryIfaceStatus(host, passwd, oids["interface"])
    if ifaces_table is None:
        continue

    for info in ifaces_table.values():
        if not info["mac_info"]:
            info["mac_info"] = ""

        if not info["ip_info"]:
            info["ip_info"] = 0
        
        if stamp_time > 0:
            recv_speed = (info["in"] * 8) / (1024.0 * stamp_time)
            send_speed = (info["out"] * 8) / (1024.0 * stamp_time)
        else:
            recv_speed = 0.00
            send_speed = 0.00

        t_out = info["out_nucast"] + info["out_ucast"]
        if t_out > 0:
            send_err = (info["out_err"] / t_out) * 100.0
            send_loss = (info["out_discards"] / t_out) * 100.0
        else:
            send_err = 0.00
            send_loss = 0.00

        t_in = info["in_nucast"] + info["in_ucast"]
        if t_in > 0:
            recv_err = (info["in_err"] / t_in) * 100.0
            recv_loss = (info["in_discards"] / t_in) * 100.0
        else:
            recv_err = 0.00
            recv_loss = 0.00

        tmp = MONITE_FORMAT_I % (check_time, monitor_id, host,
                                 info["name"], 
                                 info["ip_info"],
                                 info["mac_info"],
                                 info["status_info"],
                                 recv_err, send_err, # 接口接收错误率和发送错误率
                                 recv_loss, send_loss, # 接口接收丢包率和发送丢包率
                                 recv_speed, send_speed) # 接口接收速率和发送速率
        results.append(tmp)

    result = u'\n'.join(results) + EOL
    return result

def httpDetected(args):
'''
args:
id,ip,url,port,user,password
detect asset status by http method
use tool:
httping tool
httping -M -c 1 -f -t 3 -p 80 --url http://202.115.32.215:80/index.asp
'''
monitor_id = args[0]
hosts = args[1]
url = args[2]
user = args[4]
passwd = args[5]
port = int(args[3]) if args[3] else 80

status, avail_type, delay_time, reason, r_host = (-1 , 7, MIN_DEALY, '','')

parsed_url = urlparse(url)
# 用户未输入schema时,缺省使用http
if not parsed_url.scheme:
    url = urlunparse(["http", parsed_url.netloc, 
                      parsed_url.path, parsed_url.params, 
                      parsed_url.query, parsed_url.fragment])
elif parsed_url.scheme not in ("http", "https"):
    url = urlunparse(["http", parsed_url.netloc, 
                      parsed_url.path, parsed_url.params, 
                      parsed_url.query, parsed_url.fragment])

if user and passwd:
    cmd_withauth = "httping -M -G -c 1 -f -U '%s' -P '%s'" \
                   " -t %s --url %s"
    cmd = cmd_withauth % (user, passwd, MAX_TIMEOUT, url)
else:
    cmd_withoutauth = "httping -M -G -c 1 -f -t %s --url %s"
    cmd = cmd_withoutauth % (MAX_TIMEOUT, url)

check_time = getCurrentTime()
for host in hosts:
    r_host = host
    response_reason = u''
    for idx in xrange(MAX_RETRIES_NUM):
        debugMsg(cmd)
        retcode, outtext = getstatusoutput(cmd)
        json_data = parseHttpingResponse(outtext)
        r_status = int(json_data["status"])
        response_status = int(json_data["http_code"])
        response_reason = json_data["msg"]
        if r_status == 2 and response_status >= 300 and response_status <= 307:
            avail_type = SERVICE_STATUS_REDIRECT
            if user and passwd:
                cmd = cmd_withauth % (user, passwd,MAX_TIMEOUT, json_data["host"])
            else:
                cmd = cmd_withoutauth % (MAX_TIMEOUT, json_data["host"])
        elif r_status == 1:
            # 服务器接受请求
            if 200 <= response_status < 300:
                avail_type = SERVICE_STATUS_NORMAL
                delay_time = float(json_data["total_ms"])
                if delay_time <= 0.00:
                    delay_time = 0.10
                reason = u"目标主机返回正常状态(200 OK)"
                status = 0
            else:
                if response_status >= 300 and response_status < 400:
                    avail_type = SERVICE_STATUS_REDIRECT
                elif response_status >= 400 and response_status < 500:
                    avail_type = SERVICE_STATUS_NOT_FOUND
                elif response_status > 500:
                    avail_type = SERVICE_STATUS_UNREACHABLE
                else:
                    avail_type = SERVICE_STATUS_RESPONSE_TIMEOUT
        else:
            avail_type = SERVICE_STATUS_UNREACHABLE

        # break inner loop
        if status == 0:
            break

    # end of inner loop
    if status == 0:
        break

if not reason:
    status = 1
    avail_type = SERVICE_STATUS_UNREACHABLE
    reason = u"连接失败,错误状态(%s)" % response_reason
return (check_time, monitor_id, r_host, status, avail_type, delay_time, reason)

def httpsDetected(args):
'''
args:
id,ip,url,port,user,password
detect asset status by https method
use tool:
httping tool
httping -M -c 1 -f -t 3 -p 443 --url https://www.baidu.com:443/ --use-ssl
'''
monitor_id = args[0]
hosts = args[1]
url = args[2]
user = args[4]
passwd = args[5]
port = int(args[3]) if args[3] else 443

status, avail_type, delay_time, reason, r_host = (-1, 7, MIN_DEALY, '', '')
    
parsed_url = urlparse(url)
# 用户未输入schema时,缺省使用https
if not parsed_url.scheme:
    url = urlunparse(["https", parsed_url.netloc, 
                      parsed_url.path, parsed_url.params, 
                      parsed_url.query, parsed_url.fragment])
elif parsed_url.scheme not in ("http", "https"):
    url = urlunparse(["https", parsed_url.netloc, 
                      parsed_url.path, parsed_url.params, 
                      parsed_url.query, parsed_url.fragment])

if user and passwd:
    cmd_withauth = "httping -M -G -c 1 -f -U '%s' -P '%s'" \
                   " -t %s --url %s --use-ssl"
    cmd =  cmd_withauth % (user, passwd, MAX_TIMEOUT, url)
else:
    cmd_withoutauth = "httping -M -G -c 1 -f -t %s --url %s --use-ssl"
    cmd = cmd_withoutauth % (MAX_TIMEOUT, url)

check_time = getCurrentTime()
for host in hosts:
    r_host = host
    response_reason = u''
    for idx in xrange(MAX_RETRIES_NUM):
        debugMsg(cmd)
        retcode, outtext = getstatusoutput(cmd)
        json_data = parseHttpingResponse(outtext)

        r_status = int(json_data["status"])
        response_status = int(json_data["http_code"])
        response_reason = json_data["msg"]
        ## ???
        # https://blog.csdn.net/sdjadycsdn/article/details/80445826
        if r_status == 2 and response_status >= 300 and response_status <= 307:
            avail_type = SERVICE_STATUS_REDIRECT
            if user and passwd:
                cmd =  cmd_withauth % (user, passwd, MAX_TIMEOUT, json_data["host"])
            else:
                cmd = cmd_withoutauth % (MAX_TIMEOUT, json_data["host"])
        elif r_status == 1:
            if response_status == 200:
                avail_type = SERVICE_STATUS_NORMAL
                delay_time = float(json_data["total_ms"])
                if delay_time <= 0.00:
                    delay_time = 0.10
                reason = u"目标主机返回正常状态(200 OK)"
                status = 0
            else:
                if response_status >= 300 and response_status < 400:
                    avail_type = SERVICE_STATUS_REDIRECT
                elif response_status >= 400 and response_status < 500:
                    avail_type = SERVICE_STATUS_NOT_FOUND
                elif response_status > 500:
                    avail_type = SERVICE_STATUS_UNREACHABLE
                else:
                    avail_type = SERVICE_STATUS_RESPONSE_TIMEOUT
        else:
            avail_type = SERVICE_STATUS_UNREACHABLE

        # break inner loop
        if status == 0:
            break

    # end of inner loop
    if status == 0:
        break
# end of outter loop
if not reason:
    status = 1
    avail_type = SERVICE_STATUS_UNREACHABLE
    reason = u"连接失败,错误状态(%s)" % response_reason

return (check_time, monitor_id, r_host, status, avail_type, delay_time, reason)

def dnsDetected(args):
'''
args:
id,ip,url,port,user,password
detect asset status by dns method which support dns server
use tool:
dig command
'''
monitor_id = args[0]
hosts = args[1]
url = args[2]
status,avail_type,delay,reason,r_host = (-1,7,MIN_DEALY,'','')
try:
check_time = getCurrentTime()
for host in hosts:
r_host = host
if url:
cmd = "dig %s @%s +time=%d" % (url, host, MAX_TIMEOUT)
else:
cmd = "dig @%s +time=%d" % (host, MAX_TIMEOUT)

        debugMsg(cmd)
        result = getstatusoutput(cmd)
        dr = re.search(r'status:\s(?P\w+)',result[1])
        if dr:
            dr_status = dr.groupdict()["status"]
            if dr_status in ['NOERROR','NXDOMAIN']:                
                tr = re.search(r'Query time:\s(?P

def icmpDetected(args):
'''
args:
id,ip,url,port,user,password
detect asset status by icmp method which support icmp server
use tool:
module simplePing
'''
monitor_id = args[0]
hosts = args[1]
status,avail_type,delay_time,reason,r_host,loss_rate = (-1,7,MIN_DEALY,'','','0')
try:
check_time = getCurrentTime()
for host in hosts:
r_host = host

        cmd = 'ping -q -c 2 -w 1 %s' % (host)
        debugMsg(cmd)
        retcode, outtext = getstatusoutput(cmd)
        pr = re.search(r'rtt min/avg/max/mdev = [\d\.]+/(?P[\d\.]+)/[\d\.]+', outtext)
        if pr:
            status = 0
            delay_time = pr.groupdict().get("delay", 0.0)
            avail_type = SERVICE_STATUS_NORMAL
            loss_info = re.search(", (?P\d+)% packet loss,", outtext)
            if loss_info:
                loss_rate = loss_info.groupdict()["loss_rate"]                              
                reason = u"目标主机可达,丢包率:%s%%" % loss_rate 
            else:
                reason = u"目标主机可达"
        else:
            status = 1
            if outtext.find('100% packet loss') != -1:
                avail_type = SERVICE_STATUS_CONN_TIMEOUT
                reason = u"连接目标主机请求超时"
            elif outtext.find('time out') != -1:
                avail_type = SERVICE_STATUS_CONN_TIMEOUT
                reason = u"连接目标主机请求超时"
            elif outtext.find('source quench received') != -1:
                avail_type = SERVICE_STATUS_RESPONSE_TIMEOUT
                reason = u"目标主机繁忙无法响应"
            else:
                avail_type = SERVICE_STATUS_UNREACHABLE
                reason = u"目标主机不可达"        

        if status == 0:
            break        
except Exception:
    errMsg(u"ping {0} failed!".format(host))
    status = 1
    avail_type = SERVICE_STATUS_UNREACHABLE
    reason = u"连接失败,错误状态(Connection Failed)"
        
return (check_time, monitor_id, r_host, status, avail_type, delay_time, reason)

def tcpDetected(args):
'''
args:
id,ip,url,port,user,password
detect asset status by tcp method
use tool:
python module -- socket
'''
monitor_id = args[0]
hosts = args[1]
port = int(args[3]) if args[3] else None
status, avail_type, reason, r_host= (-1, 7, None, '')

check_time = getCurrentTime()
for host in hosts:
    address = (host, port)
    r_host = host
    if not host or not port:
        continue

    try:
        sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sockfd.settimeout(5)

        for idx in xrange(MAX_RETRIES_NUM):
            err = sockfd.connect_ex(address)
            debugMsg('[TCP] connect %s:%s => %s' % (host, port, err))
            if err in (0, EISCONN, EALREADY):
                status, avail_type, reason = 0, SERVICE_STATUS_NORMAL, u"目标主机工作正常(OK)"
                break
            elif err == ENETUNREACH:
                status, avail_type = 1, SERVICE_STATUS_UNREACHABLE
                reason = u"无法连接到目标主机(Network can't Reach)"
            elif err == EHOSTUNREACH:
                status, avail_type = 1, SERVICE_STATUS_UNREACHABLE
                reason = u"无法连接到目标主机(Host can't Reach)"
            elif err == ETIMEDOUT:
                status, avail_type = 1, SERVICE_STATUS_RESPONSE_TIMEOUT
                reason = u"目标主机繁忙,响应延时(Response Delay)"
            elif err == ECONNREFUSED:
                status, avail_type, reason = 1, SERVICE_STATUS_CONN_REFUSED, u"服务不可用"
            elif err == EAGAIN:
                try:
                    sockfd.close()
                except Exception:
                    errMsg(u"try to close sockfd errcode: {0}".format(errorcode[err]))
                finally:
                    sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    sockfd.settimeout(5)
                status, avail_type = 1, SERVICE_STATUS_CONN_REFUSED
                reason = u"无法连接到目标主机(Host can't Reach)"
            else:
                # 忽略其他错误
                # other errors
                reason = None
                warnMsg(u"other errors, errcode: {0}".format(errorcode[err]))
    except Exception:
        errMsg("[TCP] connect {0}:{1} failed!".format(host, port))
        status = 1
        avail_type = SERVICE_STATUS_UNREACHABLE
        reason = u"无法创建连接或连接超时(TimeOut)"
    finally:
        sockfd.close()

    # 只要任一IP地址可用即可
    if status == 0:
        break

if reason is not None:
    return (check_time, monitor_id, r_host, status, avail_type, 0.00, reason) 
else:
    return None

def udpDetected(args):
'''
args:
id,ip,url,port,user,password
detect asset status by udp method
use tool:
NetCat(nc) tool
nc -vuw 1
socket
'''
monitor_id = args[0]
hosts = args[1]
port = int(args[3]) if args[3] else None

status, avail_type, reason, r_host= (-1, 7, None, '')

check_time = getCurrentTime()
for host in hosts:    
    address = (host, port)
    r_host = host
    if not host or not port:
        continue

    try:
        sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sockfd.settimeout(5)

        for idx in xrange(MAX_RETRIES_NUM):
            err = sockfd.connect_ex(address)
            debugMsg('[UDP] connect %s:%s => %s' % (host, port, err))
            if err in (0, EISCONN):
                status, avail_type = 0, SERVICE_STATUS_NORMAL
                reason = u"目标主机工作正常(OK)"
                break
            elif err == ENETUNREACH:
                status, avail_type = 1, SERVICE_STATUS_UNREACHABLE
                reason = u"无法连接到目标主机(Network Can't Reach)"
            elif err == EHOSTUNREACH:
                status, avail_type = 1, SERVICE_STATUS_UNREACHABLE
                reason = u"无法连接到目标主机(Host can't Reach)"
            elif err == ETIMEDOUT:
                status, avail_type = 1, SERVICE_STATUS_RESPONSE_TIMEOUT
                reason = u"目标主机繁忙,响应延时(Response Delay)"
            elif err == ECONNREFUSED:
                status, avail_type = 1, SERVICE_STATUS_UNREACHABLE
                reason = u"服务不可用"
            elif err == EAGAIN:
                try:
                    sockfd.close()
                except Exception:
                    errMsg(u"try to close sockfd errcode: {0}".format(errorcode[err]))
                finally:
                    sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    sockfd.settimeout(5)
                status, avail_type = 1, SERVICE_STATUS_CONN_REFUSED
                reason = u"无法连接到目标主机(Host can't Reach)"
            else:
                # 忽略其他错误 (ECONNREFUSED, ECONNABORTED)
                # other errors
                reason = None
                warnMsg(u"other errors, errcode:{0}".format(errorcode[err]))
    except Exception:
        errMsg("[UDP] connect {0}:{1} failed".format(host, port))
        status, avail_type = 1, SERVICE_STATUS_UNREACHABLE
        reason = u"无法创建连接或连接超时(TimeOut)"
    finally:
        sockfd.close()

    # 只要任一IP地址可用即可
    if status == 0:
        break

if reason is not None:
    return (check_time, monitor_id, r_host, status, avail_type, 0.00, reason) 
else:
    return None

你可能感兴趣的:(2019-05-09-2)