check_mk深度剖析之C/S数据交互
了解并使用check_mk 已经有一两年了,并未深扒过其代码。由于近一年开始会写一些python 代码,在研究socket模块时,想到之前的check_mk 模块,本篇着重分析C/S 之间是如何交互数据的。
一、check_mk-agent与server端
默认在被监控主机上,只需要安装一个check_mk-agent包,由于在当前的check_mk项目站点上未找到check_mk-agent 的rpm包下载地址,这里还是使用 13年写的check_mk及WATO配置 篇里的老的agent 。直接就一个rpm,安装即可。默认安装完成后,会有以下文件:
1[root@361way ~]# rpm -ql check_mk-agent
2/etc/xinetd.d/check_mk
3/usr/bin/check_mk_agent
4/usr/bin/waitmax
5/usr/lib/check_mk_agent/local
6/usr/lib/check_mk_agent/plugins
7/usr/share/doc/check_mk_agent
8/usr/share/doc/check_mk_agent/AUTHORS
9/usr/share/doc/check_mk_agent/COPYING
10/usr/share/doc/check_mk_agent/ChangeLog
/usr/bin/check_mk_agent 程序是一个主程序为一个shell 脚本,主要作用就是收集信息,如常见的/proc下的几个目录下信息文件。将信息事先提取后,等待client 端连上来取数据 。
/etc/xinetd.d/check_mk 为xinetd 下的服务配置文件,用于守护check_mk_agent进程,并使其运行监听tcp 6556端口。
/usr/bin/waitmax 程序是做为check_mk_agent shell 脚本中调用到的一个程序,waitmax 程序用于处理shell 下的各命令在处理数据时,避免陷入僵死或长时间等待中,在其指定的最大超时时间内如果仍未结束 --- 即取回结果,就将该程序kill 掉。
/usr/lib/check_mk_agent/plugins 该目录用于存放mrpe 自定义插件。
所以单从check_mk-agent的设计上可以看出其是非常睿智的:
- 避免使用其他语言 ,仅仅使用系统自带指令即可完成基本数据的收集。
- 事先收集好数据,等待client 连接,避免监控主机长时间等待及减少监控主机的负荷。
二、python 实现的监控端
在安装完check_mk-agent 的主机上,通过telnet 127.0.0.1 6556 可以验证该插件是否正常运行,telnet指令获取的信息就是监控端需要获取的数据。如果想要实现这个功能,通过python下的socket模块可以通过如下代码实现:
1[root@361way ~]# cat client.py
2import socket
3HOST = '192.168.0.110'
4PORT = 6556
5ADDR = (HOST, PORT)
6s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
7s.connect(ADDR)
8total_data = []
9data=''
10i = 0
11while (i<100):
12 data = s.recv(1024)
13 if data:
14 total_data.append(data)
15 i+=1
16 # print total_data
17print ''.join(total_data)
18#print 'the data received is',data
19s.close()
优化以下,使用如下代码:
1[root@361way ~]# cat 2client.py
2import socket
3HOST = '192.168.0.110'
4PORT = 6556
5ADDR = (HOST, PORT)
6s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
7s.connect(ADDR)
8total_data = []
9data=''
10while True:
11 data = s.recv(1024)
12 if data:
13 total_data.append(data)
14 else:
15 break
16 # print total_data
17print ''.join(total_data)
18#print 'the data received is',data
19s.close()
为避免长时间不响应,还可以给其加一个超时器,代码如下:
1[root@361way ~]# cat socket_client.py
2import socket #for sockets
3import sys #for exit
4import struct
5import time
6#create an INET, STREAMing socket
7try:
8 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
9except socket.error:
10 print 'Failed to create socket'
11 sys.exit()
12print 'Socket Created'
13host = '192.168.0.110';
14port = 6556;
15try:
16 remote_ip = socket.gethostbyname( host )
17except socket.gaierror:
18 #could not resolve
19 print 'Hostname could not be resolved. Exiting'
20 sys.exit()
21#Connect to remote server
22s.connect((remote_ip , port))
23print 'Socket Connected to ' + host + ' on ip ' + remote_ip
24#Send some data to remote server
25def recv_timeout(the_socket,timeout=2):
26 #make socket non blocking
27 the_socket.setblocking(0)
28 #total data partwise in an array
29 total_data=[];
30 data='';
31 #beginning time
32 begin=time.time()
33 while 1:
34 #if you got some data, then break after timeout
35 if total_data and time.time()-begin > timeout:
36 break
37 #if you got no data at all, wait a little longer, twice the timeout
38 elif time.time()-begin > timeout*2:
39 break
40 #recv something
41 try:
42 data = the_socket.recv(1024)
43 if data:
44 total_data.append(data)
45 #change the beginning time for measurement
46 begin=time.time()
47 else:
48 #sleep for sometime to indicate a gap
49 time.sleep(0.1)
50 except:
51 pass
52 #join all parts to make final string
53 return ''.join(total_data)
54#get reply and print
55print recv_timeout(s)
56#Close the socket
57s.close()
上面指定的host IP为check_mk-agent 主机的IP ,在操作时,可以换成实际的IP 。check_mk官方实现该功能的代码位于modules/check_mk_base.py 文件中750行左右,具体如下:
1# Get data in case of TCP
2def get_agent_info_tcp(hostname, ipaddress, port = None):
3 if not ipaddress:
4 raise MKGeneralException("Cannot contact agent: host '%s' has no IP address." % hostname)
5 if port is None:
6 port = agent_port_of(hostname)
7 try:
8 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
9 try:
10 s.settimeout(tcp_connect_timeout)
11 except:
12 pass # some old Python versions lack settimeout(). Better ignore than fail
13 vverbose("Connecting via TCP to %s:%d.\n" % (ipaddress, port))
14 s.connect((ipaddress, port))
15 try:
16 s.setblocking(1)
17 except:
18 pass
19 output = ""
20 while True:
21 out = s.recv(4096, socket.MSG_WAITALL)
22 if out and len(out) > 0:
23 output += out
24 else:
25 break
26 s.close()
27 if len(output) == 0: # may be caused by xinetd not allowing our address
28 raise MKAgentError("Empty output from agent at TCP port %d" % port)
29 return output
30 except MKAgentError, e:
31 raise
32 except MKCheckTimeout:
33 raise
34 except Exception, e:
35 raise MKAgentError("Cannot get data from TCP port %s:%d: %s" %
36 (ipaddress, port, e))
可以看到官方接收tcp数据部分接近2client.py部分 ,不过每次读取1pagesize(4k)大小的数据,增加了socket.MSG_WAITALL ---在socket模块中socket.MSG_WAITALL 值默认为256 ,其是阻塞模式下尽量读全数据的参数。
三、总结
从代码中可以看出check_mk 在C/S交互部分处理的非常好。将nrpe 模式下的采集数据的工作主要交给了被监控端,这里的被监控端是主动的 。监控端所做的工作就是接收数据,在接收到本地后,再对数据进行处理。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/check_mk-cs-data-interaction/4255.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.