最近发现有几台ftp服务器非常不稳定,造成 服务不可用,最要命的是都是用户报上来的,这种事完全违背咱们运维高大上自动化监控水准,经查发现之前管理员没加ftp应用监控,NND,原来一直在无政府状态下工作呀,现在到我手里,就不能任由你们了,做运维的都知道,不怕有问题,就怕你发现不了或者出现了问题,好几天才知道,当然如果boss比你先知道,你就只能呵呵了,所以呢,本着对工作负责的态度,今天咱们就要给所有ftp服务器个监控,基本思路是检查ftp服务的可用性,发现有问题就通知管理员,因为需求比较简单,都自己写了个python脚本实现了,前戏如下:
1、在每台ftp服务器上创建一个ftp用户用来检查ftp登录测试。
2、提供一个配置文件,可以由用户自己配置要检查的服务器列表。
3、然后程序根据提供的用户名称和密码登录每台ftp测试是否成功,判断成功或失败,然后将反馈的状体写入status.txt文件中。
4、因为ftp服务器比较多,所以脚本采用的线程方式运行。
全部代码如下,稍后解释:
#encoding=utf-8
#__author__ = 'glacier'
#date:20151025
import os.path
import ConfigParser
from ftplib import FTP_TLS
from threading import Thread
import socket
import ssl
cf = ConfigParser.ConfigParser()
cf.read(r'e:\project1\ftplist.txt')
user = 'check_login'
password = '45H'
server_info = []
#定义FTP_TLS类
class IMPLICIT_FTP_TLS(FTP_TLS):
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
certfile=None, timeout=60):
FTP_TLS.__init__(self, host, user, passwd, acct, keyfile, certfile, timeout)
def connect(self, host='', port=0, timeout=-1):
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -1:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
#self.af = self.sock.family
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
self.file = self.sock.makefile('rb')
self.welcome = self.file.readline()
except Exception as e:
print e
return self.welcome
#获得配置文件信息,转换成列表
def get_ip_port():
for arg in cf.sections():
ip, port = cf.options(arg)
ip = cf.get(arg, ip)
port = cf.get(arg, port)
info = (ip, port)
server_info.append(info)
return server_info
#检查函数,测试是否ftp登录ok
def check_login(ftp_server, ftp_port):
try:
ftps = IMPLICIT_FTP_TLS()
#print help(ftps)
ftps.connect(host=ftp_server, port=ftp_port)
ftps.login(user=user, passwd=password)
ftps.quit()
return 1
except:
return 0
#根据检查的成功或失败,写入文件
def write_status(ftp_server, ftp_port):
result = check_login(ftp_server, ftp_port)
f = open(r'e:\project1\status.txt', 'a+')
if result == 1:
f.write(ftp_server + ' login ok' + '\n')
else:
f.write(ftp_server + ' login error' + '\n')
f.close()
#主函数,判断文件大小是否为0,非0重置文件,保持文件内容最新,多线程检查。
if __name__ == '__main__':
threads = []
server_info = get_ip_port()
if os.path.getsize(r'e:\project1\status.txt'):
f = open(r'e:\project1\status.txt', 'r+')
f.truncate()
f.close()
for i in range(0, len(cf.sections())):
ip, port = server_info[i]
threads.append(Thread(target=write_status, args=(ip, port)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
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
#encoding=utf-8
#__author__ = 'glacier'
#date:20151025
importos.path
importConfigParser
fromftplibimportFTP_TLS
fromthreadingimportThread
importsocket
importssl
cf=ConfigParser.ConfigParser()
cf.read(r'e:\project1\ftplist.txt')
user='check_login'
password='45H'
server_info=[]
#定义FTP_TLS类
classIMPLICIT_FTP_TLS(FTP_TLS):
def__init__(self,host='',user='',passwd='',acct='',keyfile=None,
certfile=None,timeout=60):
FTP_TLS.__init__(self,host,user,passwd,acct,keyfile,certfile,timeout)
defconnect(self,host='',port=0,timeout=-1):
ifhost!='':
self.host=host
ifport>0:
self.port=port
iftimeout!=-1:
self.timeout=timeout
try:
self.sock=socket.create_connection((self.host,self.port),self.timeout)
#self.af = self.sock.family
self.sock=ssl.wrap_socket(self.sock,self.keyfile,self.certfile)
self.file=self.sock.makefile('rb')
self.welcome=self.file.readline()
exceptExceptionase:
printe
returnself.welcome
#获得配置文件信息,转换成列表
defget_ip_port():
forargincf.sections():
ip,port=cf.options(arg)
ip=cf.get(arg,ip)
port=cf.get(arg,port)
info=(ip,port)
server_info.append(info)
returnserver_info
#检查函数,测试是否ftp登录ok
defcheck_login(ftp_server,ftp_port):
try:
ftps=IMPLICIT_FTP_TLS()
#print help(ftps)
ftps.connect(host=ftp_server,port=ftp_port)
ftps.login(user=user,passwd=password)
ftps.quit()
return1
except:
return0
#根据检查的成功或失败,写入文件
defwrite_status(ftp_server,ftp_port):
result=check_login(ftp_server,ftp_port)
f=open(r'e:\project1\status.txt','a+')
ifresult==1:
f.write(ftp_server+' login ok'+'\n')
else:
f.write(ftp_server+' login error'+'\n')
f.close()
#主函数,判断文件大小是否为0,非0重置文件,保持文件内容最新,多线程检查。
if__name__=='__main__':
threads=[]
server_info=get_ip_port()
ifos.path.getsize(r'e:\project1\status.txt'):
f=open(r'e:\project1\status.txt','r+')
f.truncate()
f.close()
foriinrange(0,len(cf.sections())):
ip,port=server_info[i]
threads.append(Thread(target=write_status,args=(ip,port)))
forthreadinthreads:
thread.start()
forthreadinthreads:
thread.join()
开始先定义了一个类,用来做加密传输,前面已经说了,我的ftp都是加密传输的,所以要ssl socket 进行封装建立一条加密的socket,get_ip_port()函数是从配置文件中获取要检查的ftp server信息,返回一个列表,check_login()函数是进行模拟登录的函数,如何成返回1,否则返回0,write_status()函数是根据check_login()函数返回的结果,将状态信息写入状态文件中。
因为每次都要获取最新的状态内容,所以每次程序检查前要判断status.txt文件是否有内容,如果有要就删除,写入最新的状态检查内容,os.path.getsize()函数是判断文件是否为0,如果不为0,就是返回真值,就打开文件,f.truncat()清空文件内容,然后进入线程执行部分,开始一个for循环是根据配置文件中返回的sections长度作为循环的条件,然后把每个线程加入一个线程列表,然后循环线程列表,开始thread.start(),最后一个for循环是等待线程结束thread.join(),即主线程不退出等待所有线程结束后退出,写到这基本的程序就介绍完了,接下来要说如何部署了。
部署:
1、编辑crontab ,每三十分钟检查一次。
*/30 * * * * python /root/scripts/check_ftp_status.py
2、写一个脚本,检查生成的status.txt文件是否有有error,如果有发邮件给管理员,因为这个脚本很简单,我就不贴了,我相信懂点shell脚本的兄弟肯定没问题,如果真有问题,可以留言给我,我发你,还有这个脚本也是要放入crontab中的,因为要定时检查。
写在最后:
因为我的ftp是加密传输的,所以会稍微复杂一些,因为要封装一个加密的socket,要先定义一个类,如果不是加密传输的ftp,会更简单,直接调用 FTP这个模块类就可以了,具体内容可以看官方文档。
另外这种监控方式还是比较low,因为急用,所以就先上了,当然比较好点的是写一个程序来读取生成的文件内容,展示到web上,定时刷新一下,就可以看到最新的状态结果了,这个程序后续有精力我就会写,当然博客就不更新了,代码会放入github上,需要的朋友可以关注,查看更新。
最后说明,因为我是在windows下编写的,所以测试都是用的windows目录,如果哪位兄弟用在linux下,可以自行修改目录和配置文件地址。