苦逼的运维工程师,每天做着重复的工作,如果没有自动化的工具协助,真的是无法面对繁重的工作。尤其是服务器、交换机需要24小时在线,运维工程师不可能24小上班,于是自动化运维工具必不可少。
自从学习python已有半年时间,最近完成了一个python脚本,实现五分钟巡检一次,并将不通的地址发送邮件通知。
实现条件:1、在.py文件同目录下建立doip.txt,里面保存要巡检的IP地址。如下图:
具体代码如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import re import datetime from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr import smtplib import time def ceshi01(ip,jieguo): jieguo='' mingling = 'ping ' + ip + ' -n 1' # 形成ping命令 # print(mingling) ping = os.popen(mingling).read() # 执行1次ping命令 #print(ping) if re.compile(r'来自..+', re.M).findall(ping): # 判断是否通 jieguo = '通' else: jieguo = '不通' return jieguo def sendmail(ip): def _format_addr(s): name, addr = parseaddr(s) #print(name, addr) return formataddr((Header(name, 'utf-8').encode(), addr)) # Email地址和口令 from_addr = '*******@126.com' password = '*******' # 收件人地址 to_addr = '*******@126.com' # SMTP服务器地址 smtp_server = 'smtp.126.com' # 参数1.邮件正文 参数2MIME的subtype,plain表示纯文本,最终的MIME就是text/plain, # 最后一定要用utf-8编码保证多语言的兼容性 # 如果发送HTML邮件 把HTML字符串传进去 把plain变为html msg = MIMEText('IP地址为'+str(ip), 'plain', 'utf-8') # 注意不能简单地传入name,因为如果包含中文,需要通过Header对象进行编码。 msg['From'] = _format_addr('管理员<%s>' % from_addr) # msg['To']接收的是字符串而不是list,如果有多个邮件地址,用,分隔即可。 # 你看到的收件人的名字很可能不是我们传入的管理员,因为很多邮件服务商在显示邮件时, # 会把收件人名字自动替换为用户注册的名字,但是其他收件人名字的显示不受影响。 msg['To'] = _format_addr('管理员<%s>' % to_addr) msg['Subject'] = Header('巡检结果', 'utf-8').encode() # SMTP协议默认端口是25 server = smtplib.SMTP(smtp_server, 25) # 打印出和SMTP服务器交互的所有信息。 # SMTP协议就是简单的文本命令和响应。 # server.set_debuglevel(1) # 用来登录SMTP服务器 server.login(from_addr, password) # 发邮件,可以发给多个人,所以是一个list,邮件正文是一个str,as_string()把MIMEText对象变成str server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit() print('邮件发送成功') def task(): b=0 while True: b +=1 time.sleep(300) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') print(ts,'开始测试','第%d次。'%(b)) pathip = open('doip.txt','r')#以中读方式打开目标文件 ipline = pathip.readlines()#读取文件中所有内容到列表ipline中 #print(ipline) for i in range(len(ipline)):#循环次数为IP地址个数 ip = ipline[i].split()#赋值列表文件 ip = str(ip)#转换成字符串 #print(ip) ip = ip[2:-2]#截取字符串 #print(ip,type(ip)) jieguo='' jieguo=ceshi01(ip,jieguo)#接收返回结果 ipline[i] = ip + jieguo #print(ip,jieguo) #if jieguo=='不通': # sendmail(ip,jieguo) # print('邮件发送成功') print(ipline) # sendmail(ipline) a=[] for j in range(len(ipline)): if ipline[j].find('不')>0: a.append(ipline[j]) if a != []: sendmail(a) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') print(ts,'结束测试','第%d次。'%(b)) pathip.close() task()
脚本缺点:1、没有实现交互式IP地址填写功能,读取不到文件也不会提示报错。
11月16日脚本改善:
些脚本地运行一段时间后,发现有误现象,即脚本中ping命令只执行一次,对于一些设备来说,ping一次超时不代表此设备down机,于是现改善为ping五次,有3次不通才发邮件报警。
代码如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import re import datetime from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr import smtplib import time def ceshi01(ip,jieguo): jieguo='' mingling = 'ping ' + ip + ' -n 5' # 形成ping命令 # print(mingling) ping = os.popen(mingling).read() # 执行1次ping命令 #print(ping) if re.compile(r'来自..+', re.M).findall(ping): # 判断是否通 jieguo = '通' else: jieguo = '不通' return jieguo def sendmail(ip): def _format_addr(s): name, addr = parseaddr(s) #print(name, addr) return formataddr((Header(name, 'utf-8').encode(), addr)) # Email地址和口令 from_addr = '*******@126.com' password = '*******' # 收件人地址 to_addr = '*******@126.com' # SMTP服务器地址 smtp_server = 'smtp.126.com' # 参数1.邮件正文 参数2MIME的subtype,plain表示纯文本,最终的MIME就是text/plain, # 最后一定要用utf-8编码保证多语言的兼容性 # 如果发送HTML邮件 把HTML字符串传进去 把plain变为html msg = MIMEText('IP地址为'+str(ip), 'plain', 'utf-8') # 注意不能简单地传入name,因为如果包含中文,需要通过Header对象进行编码。 msg['From'] = _format_addr('管理员<%s>' % from_addr) # msg['To']接收的是字符串而不是list,如果有多个邮件地址,用,分隔即可。 # 你看到的收件人的名字很可能不是我们传入的管理员,因为很多邮件服务商在显示邮件时, # 会把收件人名字自动替换为用户注册的名字,但是其他收件人名字的显示不受影响。 msg['To'] = _format_addr('管理员<%s>' % to_addr) msg['Subject'] = Header('巡检结果', 'utf-8').encode() # SMTP协议默认端口是25 server = smtplib.SMTP(smtp_server, 25) # 打印出和SMTP服务器交互的所有信息。 # SMTP协议就是简单的文本命令和响应。 # server.set_debuglevel(1) # 用来登录SMTP服务器 server.login(from_addr, password) # 发邮件,可以发给多个人,所以是一个list,邮件正文是一个str,as_string()把MIMEText对象变成str server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit() print('邮件发送成功') def task(): b=0 while True: b +=1 time.sleep(300) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') print(ts,'开始测试','第%d次。'%(b)) pathip = open('doip.txt','r')#以中读方式打开目标文件 ipline = pathip.readlines()#读取文件中所有内容到列表ipline中 #print(ipline) for i in range(len(ipline)):#循环次数为IP地址个数 ip = ipline[i].split()#赋值列表文件 ip = str(ip)#转换成字符串 #print(ip) ip = ip[2:-2]#截取字符串 #print(ip,type(ip)) jieguo='' jieguo=ceshi01(ip,jieguo)#接收返回结果 ipline[i] = ip + jieguo #print(ip,jieguo) #if jieguo=='不通': # sendmail(ip,jieguo) # print('邮件发送成功') print(ipline) # sendmail(ipline) a=[] for j in range(len(ipline)): if ipline[j].find('不')>3: a.append(ipline[j]) if a != []: sendmail(a) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') print(ts,'结束测试','第%d次。'%(b)) pathip.close() task()
脚本缺点:1、邮件地址没有实现自动读取。
2019年11月21日更新:
改善了邮箱信息自动读取的功能。
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import re import datetime from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr import smtplib import time def ceshi01(ip,jieguo): jieguo='' mingling = 'ping ' + ip + ' -n 5' # 形成ping命令 # print(mingling) ping = os.popen(mingling).read() # 执行1次ping命令 #print(ping) if re.compile(r'来自..+', re.M).findall(ping): # 判断是否通 jieguo = '通' else: jieguo = '不通' return jieguo def sendmail(ip): file = open(r'youjian.txt', 'r') lenfile = file.readlines() # Email地址 from_addr = lenfile[0].strip() # 口令 password = lenfile[1].strip() # 收件人地址 to_addr = lenfile[2].strip() # SMTP服务器地址 smtp_server = lenfile[3].strip() file.close() try: def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) # 参数1.邮件正文 参数2MIME的subtype,plain表示纯文本,最终的MIME就是text/plain, # 最后一定要用utf-8编码保证多语言的兼容性 # 如果发送HTML邮件 把HTML字符串传进去 把plain变为html msg = MIMEText('IP地址为。。。服务器报警', 'plain', 'utf-8') # 注意不能简单地传入name,因为如果包含中文,需要通过Header对象进行编码。 msg['From'] = _format_addr('管理员 <%s>' % from_addr) # msg['To']接收的是字符串而不是list,如果有多个邮件地址,用,分隔即可。 # 你看到的收件人的名字很可能不是我们传入的管理员,因为很多邮件服务商在显示邮件时, # 会把收件人名字自动替换为用户注册的名字,但是其他收件人名字的显示不受影响。 msg['To'] = _format_addr('管理员 <%s>' % to_addr) msg['Subject'] = Header('报警提醒', 'utf-8').encode() # SMTP协议默认端口是25 server = smtplib.SMTP(smtp_server, 25) # 打印出和SMTP服务器交互的所有信息。 # SMTP协议就是简单的文本命令和响应。 # server.set_debuglevel(1) # 用来登录SMTP服务器 server.login(from_addr, password) print('发送成功') # 发邮件,可以发给多个人,所以是一个list,邮件正文是一个str,as_string()把MIMEText对象变成str server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit() except Exception as e: print(e) def task(): b=0 while True: b +=1 time.sleep(300) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') print(ts,'开始测试','第%d次。'%(b)) pathip = open('doip.txt','r')#以中读方式打开目标文件 ipline = pathip.readlines()#读取文件中所有内容到列表ipline中 #print(ipline) for i in range(len(ipline)):#循环次数为IP地址个数 ip = ipline[i].split()#赋值列表文件 ip = str(ip)#转换成字符串 #print(ip) ip = ip[2:-2]#截取字符串 #print(ip,type(ip)) jieguo='' jieguo=ceshi01(ip,jieguo)#接收返回结果 ipline[i] = ip + jieguo #print(ip,jieguo) #if jieguo=='不通': # sendmail(ip,jieguo) # print('邮件发送成功') print(ipline) # sendmail(ipline) a=[] for j in range(len(ipline)): if ipline[j].find('不')>2: a.append(ipline[j]) if a != []: sendmail(a) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') print(ts,'结束测试','第%d次。'%(b)) pathip.close() task()
功能整理如下:
1、利用python实现自动巡检功能。每五分钟自动执行一次。
2、实现原理:利用ping命令,测试ip地址是否连通,每次发送5个ping包,当有3次不通时,发送邮件报警。
3、待测试的ip地址通过文件读取(ip地址可变,实现了灵活性)。
4、待发送的邮箱地址通过文件读取(邮箱地址不在脚本中体现,实现了安全性)。
缺点:
1、没有图形界面。
2019年12月1日更新:
完成了python脚本,运维自动化(自动巡检功能),隔一断时间ping一次主机,将不通的主机IP地址发送指定邮箱。
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'X0601.ui' # # Created by: PyQt5 UI code generator 5.13.0 # # WARNING! All changes made in this file will be lost! import sys,os from PyQt5.QtCore import QThread, pyqtSignal, QDateTime, QObject from PyQt5.QtWidgets import QApplication, QDialog, QLineEdit if hasattr(sys, 'frozen'): os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH'] import time from PyQt5 import QtCore, QtGui, QtWidgets import datetime import re from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr import smtplib class BackendThread0(QObject): # 通过类成员对象定义信号 update_date0 = pyqtSignal(str) # 处理业务逻辑 def run0(self): while True: data0 = QDateTime.currentDateTime() currTime = data0.toString("yyyy-MM-dd hh:mm:ss") self.update_date0.emit(str(currTime)) time.sleep(1) class BackendThread1(QObject): # 通过类成员对象定义信号 update_date1 = pyqtSignal(str) # 处理业务逻辑 def run1(self): b = 0 ts_sum = '' while True: b += 1 time.sleep(5) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') ts_sum = ts_sum + ts ts = '开始测试'+'第'+str(b)+'次。' ts_sum = ts_sum + ts + '\n' #print(ts, '开始测试', '第%d次。' % (b)) pathip = open('doip.txt', 'r') # 以中读方式打开目标文件 ipline = pathip.readlines() # 读取文件中所有内容到列表ipline中 # print(ipline) for i in range(len(ipline)): # 循环次数为IP地址个数 ip = ipline[i].split() # 赋值列表文件 ip = str(ip) # 转换成字符串 # print(ip) ip = ip[2:-2] # 截取字符串 # print(ip,type(ip)) jieguo = '' mingling = 'ping ' + ip + ' -n 5' # 形成ping命令 ping = os.popen(mingling).read() # 执行1次ping命令 if re.compile(r'来自..+', re.M).findall(ping): # 判断是否通 jieguo = '通' else: jieguo = '不通' ipline[i] = ip + jieguo #print(ipline) ts_sum = ts_sum + str(ipline) +'\n' a = [] for j in range(len(ipline)): if ipline[j].find('不') > 2: a.append(ipline[j]) if a != []: # sendmail(a) file = open(r'youjian.txt', 'r') lenfile = file.readlines() from_addr = lenfile[0].strip() password = lenfile[1].strip() to_addr = lenfile[2].strip() smtp_server = lenfile[3].strip() file.close() try: def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) msg = MIMEText('IP地址为'+str(a)+'设备报警', 'plain', 'utf-8') msg['From'] = _format_addr('管理员 <%s>' % from_addr) msg['To'] = _format_addr('管理员 <%s>' % to_addr) msg['Subject'] = Header('报警提醒', 'utf-8').encode() server = smtplib.SMTP(smtp_server, 25) server.login(from_addr, password) #print('发送成功') server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit() except Exception as e: print(e) now = datetime.datetime.now() ts = now.strftime('%Y-%m-%d %H:%M:%S') ts_sum = ts_sum + ts #print(ts, '结束测试', '第%d次。' % (b)) ts = '结束测试' + '第' + str(b) + '次。' ts_sum = ts_sum + ts + '\n' + '\n' pathip.close() self.update_date1.emit(str(ts_sum)) class Window(QDialog): def __init__(self): QDialog.__init__(self) self.setWindowTitle('PyQt 5自动化巡检') self.resize(400,300) self.input0=QLineEdit(self) self.input0.resize(400,50) self.input1=QtWidgets.QTextEdit(self) self.input1.resize(50,50) self.input1.setGeometry(QtCore.QRect(0,49,400, 300)) self.initUI() def initUI(self): # 创建线程 self.backend = BackendThread0() self.backend1 = BackendThread1() # 连接信号 self.backend.update_date0.connect(self.handleDisplay0) self.backend1.update_date1.connect(self.handleDisplay1) self.thread = QThread() self.thread1 = QThread() self.backend.moveToThread(self.thread) self.backend1.moveToThread(self.thread1) # 开始线程 self.thread.started.connect(self.backend.run0) self.thread1.started.connect(self.backend1.run1) self.thread.start() self.thread1.start() # 将当前时间输出到文本框 def handleDisplay0(self, data0): self.input0.setText(data0) def handleDisplay1(self, data1): self.input1.setText(data1) if __name__ == '__main__': app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec_())
运行条件:
1、同目录下有doip.txt(存放待巡检IP地址)和youjian.txt(存放邮箱地址)