TCP端口监控及IOS平台通知脚本

时候不早了,简单介绍下实现的背景及脚本功能。

背景
由于本人购置了两台云服务器,一台阿里云学生主机,国内做做实验什么的,一台在国外搭个梯子,顺便挂个BLOG,一直想写个监控脚本,一边放在国内的主机上对国外的vps进行监控,一边放在国外的主机上对阿里云主机进行监控,一直想自己写脚本,感觉Zabbix/nagios等监控软件太笨拙,有种杀猪焉用宰牛刀的味道,而我一直想要一种实时推送的功能,不是邮件推送。

前几天看到Tyr使用了Pushover这个神器,觉得还不错,所以就试试。

实现的监控效果:

以阿里云为例:每60s对国外的vps的nginxshadowsocks server进行基于端口的健康检查。当某个服务不可用会发送一次IOS平台实时提醒,并会继续监控剩下存活的服务端口,当down掉的服务被检查出存活时,会重新发送一次提醒。在一天后,如果网站被监控端口开发正常,发送健康消息通知。同理,在国外的vps运行不同参数的脚本,对阿里云的开放tcp服务端口进行监控。


pushover

pushover

Pushover提供可一个实时性很强的可调用的接口,我们只需要在脚本中调用这个接口,就可以给我的Iphone推送通知。

首先我们需要iOS上安装Pushover这个APP并完成用户的注册,注册和登录完成后,打开pushover的官网,进入后台管理后我们就可以在网页上向自己的设备发送推送消息了。

我们要注册这个网站的服务,之后会拿到User Key,之后在APPS & Plugins添加自己的Send a Notification,会拿到自己程序的API Token

这两个参数是pushover服务的重要参数。

具体可以看官网的API操作或者Tyr的博客

初步完成通知部分code如下:

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
def pushover(port = None):
url = 'https://api.pushover.net/1/messages.json'
token = 'ayegkcthu8oycfscgbfkzfs1j5g'
user = 'u5i63n7yu16dm1mn3ba9iuzd96'
'''
the token and user i had changed , you can use your own
'''
title = "zhxfei's site monitor"
port_message = {
0 : "your server is down",
80 : "your website zhxfei's notes is down",
81 : "your website zhxfei's notes is on",
100 : "your shadowsocks server is down",
101 : "your shadowsocks server is on",
1001 : "your shadowsocks client is on",
1002 : "your shadowsocks client is down",
10001 : "your polipo is down",
10002 : "your polipo is on",
200 : "your server is healthy"
}
message = port_message.get(port)
if message is None:
message = "Your code has some problem"
body = {
'token': token,
'user': user,
'message': message,
'title': title
}
body = urllib.urlencode(body)
request = urllib2.Request(url, body)
request.add_header('Content-type', 'application/x-www-form-urlencoded')
response = urllib2.urlopen(request).read()
return response

使用:
以阿里云为例:
python monitor.py 133.130.x.x 1001 80 &

在被监控端

1
2
3
4
5
[root@zhxfei.com ~]# systemctl stop nginx.service
[root@zhxfei.com ~]# systemctl start nginx.service
[root@zhxfei.com ~]# kill 28564
[root@zhxfei.com ~]# netstat -tunlp | grep 1001
[root@zhxfei.com ~]# systemctl stop nginx.service

可以看到手机上的提醒:

在国外运行的脚本只要加上被监控主机修的ip,端口重新运行即可。


更新:适用运行了几天,没发现什么问题,每天都能收到2个healthy notification,但是发现pushover不是个免费的啊….

小伙伴请谨慎使用~

SMTP

好吧,如果不想使用pushover,也可以使用smtp,简单修改下代码就可以,关于SMTP的部分代码如下:

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
from email.mime.text import MIMEText
from email import encoders
from email.header import Header
from email.utils import parseaddr,formataddr
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
def smtp_noti(port):
port_message = {
0 : "your server is down",
80 : "your website zhxfei's notes is down",
81 : "your website zhxfei's notes is on",
100 : "your shadowsocks server is down",
101 : "your shadowsocks server is on",
1001 : "your shadowsocks client is on",
1002 : "your shadowsocks client is down",
10001 : "your polipo is down",
10002 : "your polipo is on",
200 : "your server is healthy"
}
message = port_message.get(port)
if message is None:
message = "Your code has some problem"
from_addr = '15852937839@163.com'
password = 'xxxxxx'
to_addr = '2496199664@qq.com'
msg = MIMEText(message,'plain','utf-8')
msg['From'] = _format_addr("zhxfei's site monitor <%s>" % from_addr)
msg['To'] = _format_addr('adminnistor <%s>' % to_addr)
msg['Subject'] = Header('tcp site monitor', 'utf-8').encode()
server = smtplib.SMTP('smtp.163.com',25)
server.set_debuglevel(1)
server.login(from_addr,password)
server.sendmail(from_addr,[to_addr,],msg.as_string())
server.quit()

其中:from_addrpassword是你需要设置的作为监控邮件发起方的账号和密码,to_addr是监控邮件的接收方,并且可以设置成一个列表,可以发送给多个邮件账号。

看下效果吧:

down

on

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
#!/usr/local/python
# _*_ coding:utf-8
import urllib
import urllib2
import os
import socket
import time
import sys
def monitor(ip,port):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
s.connect(ip,port)
s.shutdown(2)
return True
except Exception,e:
return False
def pushover(port = None):
url = 'https://api.pushover.net/1/messages.json'
token = 'ayegkcthu8oycfscgbfkzfs1j5g'
user = 'u5i63n7yu16dm1mn3ba9iuzd96'
'''
the token and user i had changed , you can use your own
'''
title = "zhxfei's site monitor"
port_message = {
0 : "your server is down",
80 : "your website zhxfei's notes is down",
81 : "your website zhxfei's notes is on",
100 : "your shadowsocks server is down",
101 : "your shadowsocks server is on",
1001 : "your shadowsocks client is on",
1002 : "your shadowsocks client is down",
10001 : "your polipo is down",
10002 : "your polipo is on",
200 : "your server is healthy"
}
message = port_message.get(port)
if message is None:
message = "Your code has some problem"
body = {
'token': token,
'user': user,
'message': message,
'title': title
}
body = urllib.urlencode(body)
request = urllib2.Request(url, body)
request.add_header('Content-type', 'application/x-www-form-urlencoded')
response = urllib2.urlopen(request).read()
return response
def status_check(port_status):
for v in port_status.values():
if not v:
return False
return True
if __name__ == '__main__':
if len(sys.argv) < 3:
print '''
Usage: {} IP port ....
like this: {} 120.10.10.10 22 80 443'''.format(sys.argv[0],sys.argv[0])
sys.exit(1)
ip = sys.argv[1]
port_list = sys.argv[2:]
port_status = dict(zip(map(int,port_list),len(port_list)*[1]))
'''
port_status = {
80 : 1, # 1 means the vps's deamon is on before health check
443: 1
}
'''
count = 0
while True:
for port,status in port_status.items():
if status == 0 and monitor(ip,port):
pushover(port+1)
port_status[port] = 1
elif status and monitor(ip,port) is False:
pushover(port)
port_status[port] = 0
count += 1
if count > 1440 and status_check(port_status):
pushover(200)
count = 0
print "port_status:",port_status
time.sleep(60)
坚持原创技术分享,您的支持将鼓励我继续创作!