苦逼的运维工程师,每天做着重复的工作,如果没有自动化的工具协助,真的是无法面对繁重的工作。尤其是服务器、交换机需要24小时在线,运维工程师不可能24小上班,于是自动化运维工具必不可少。

      自从学习python已有半年时间,最近完成了一个python脚本,实现五分钟巡检一次,并将不通的地址发送邮件通知。

实现条件:1、在.py文件同目录下建立doip.txt,里面保存要巡检的IP地址。如下图:

                         python实现运维自动巡检功能,五分钟巡检一次,并将不通的地址发送邮件通知_第1张图片


具体代码如下:

#!/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、待发送的邮箱地址通过文件读取(邮箱地址不在脚本中体现,实现了安全性)。

python实现运维自动巡检功能,五分钟巡检一次,并将不通的地址发送邮件通知_第2张图片

python实现运维自动巡检功能,五分钟巡检一次,并将不通的地址发送邮件通知_第3张图片




缺点:

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(存放邮箱地址)