基于python的服务器状态监测和邮件上报脚本
事情是这样的。最近实验室的服务器有点不稳定,出现了几次ssh连接莫名其妙中断的问题,严重干扰了大家的工作进度。
为了排查问题原因,也同时为了未来能够更好的应对此类问题,今天下午弄了个python脚本,实现了服务器状态监测+邮件上报两个功能。配合Linux的crontab功能 ,可以实现定时检查状态+更新。其中,服务器状态监测通过直接调用shell指令实现,而邮件上报通过python标准库smtplib实现——其中涉及到了不少新知识。
本文是对探索记录的详细记录,包括对smtplib的介绍,以及整个脚本编写和配置的全过程。
一、背景知识
(一)关于邮件:一些计算机网络的相关知识
下图为教材《计算机网络: 自顶向下方法》(原书第7版)的截图。简单来说,电子邮件和网页一样也是一种运行在Internet应用层的东西,也有一些属于自己的通信协议,这些协议包括SMTP(发邮件)、POP3(接收邮件)、IMAP(双向同步协议)。
三种通信协议:
- SMTP(Simple Mail Transfer Protocol) 负责邮件的发送和中继,是邮件从客户端到服务器、再到目标服务器的核心协议。
- POP3(Post Office Protocol Version 3) 负责用户从邮件服务器下载邮件到本地客户端,下载后通常会从服务器删除邮件。
- IMAP(Internet Message Access Protocol) 允许用户在线同步邮件,支持多设备访问同一邮箱,保留邮件在服务器上。
邮件客户端(如Outlook、Gmail网页端)通过以下步骤与协议交互:
- 发送邮件:
- 使用SMTP协议连接到发件服务器。
- 验证用户身份(如输入邮箱和密码)。
- 通过SMTP命令将邮件内容发送到目标服务器。
- 接收邮件:
- 通过POP3/IMAP协议连接到收件服务器。
- 下载邮件到本地(POP3)或在线查看(IMAP)。
- (可选)删除服务器上的邮件(仅POP3)。
如果我们只想要实现发邮件功能的话,SMTP是我们所需。
下图展示了邮件客户端通过SMTP协议发送邮件的一个简化的步骤,可以看到客户端总是和自己的邮件服务器进行交互,而邮件的发送过程则是在服务器之间进行。这是因为电子邮件是一种异步通信媒介,即当人们方便时就可以收发邮件,不必与他人的计划进行协调(当收件人不在电脑旁边时,邮件将由服务器代为保管)。
(二)python的邮件库smtplib
参考python标准库文档: smtplib
— SMTP 协议客户端
smtplib
模块定义了一个 SMTP 客户端会话对象,该对象可将邮件发送到互联网上任何带有 SMTP 或 ESMTP 监听程序的计算机。其定义了三个很常用的类: smtplib.SMTP
, smtplib.SMTP_SSL
, smtplib.LMTP
,封装了不同类型的SMTP连接的方法。由于我们这里使用的是QQ邮箱,其只支持SSL连接,因此下面我们以smtplib.SMTP_SSL
为例开展讲解。
首先,我们需要通过smtplib.SMTP_SSL
构建一个SMTP的连接实例:
1 | smtp = smtplib.SMTP_SSL('smtp.qq.com',465) # 第一个参数是QQ邮箱的SMTP服务器域名,第二个参数是SMTP服务器的端口号。 |
这样的一个实例对象 smtp
拥有许多可以调用的方法,包括 connect
, login
, auth
, sendmail
等。要发送一封邮件,我们需要依次调用一系列方法(登录服务器,发送邮件,退出登录)。示例如下:
1 | smtp = smtplib.SMTP_SSL('smtp.qq.com',465) |
上述API的具体使用方法以及参数列表,可以查看官方文档 。
需要注意的是,由于邮件协议的特殊性,邮件内容无法直接发送,需要先构建MIMEText对象,然后调用 as_string()
方法转化为ASCII编码的plain text(如下图)。关于MIMEText对象的构建方法,可以参考官方文档 email.mime
: 从头创建电子邮件和 MIME 对象 。
(三)邮件客户端的密钥设置
为了提高安全性,市面上主流的邮箱都提供了POP3/IMAP/SMTP 服务的单独密钥设置,这个密钥用于配置客户端,与浏览器端的登陆密码不同,需要单独获取。
获取密钥(”授权码”)的教程在网上有许多,读者朋友们也可以参考下面这些教程:
(三)python的shell指令执行方法
有两种:
os.system(<command>)
:直接运行指令,一切shell指令的输出全部定向到标准输出流,返回值为shell指令的status code。os.popen(<command>)
:构建一个popen对象,这个对象类似于一个file对象,但是其内容是指令的运行结果。需要调用read()
方法获得shell指令的输出内容。
我们需要捕获shell指令的输出内容,因此需要用第二种方法。
二、脚本内容
1. 导入一些包
1 | import socket,os,sys |
2. 运行指令,查询服务器状态
我们将依次运行这些指令,并将结果以HTML格式的文本作为返回值(电子邮件支持HTML格式的富文本内容)。
1 | # 定义一个函数,运行shell command,返回运行结果 |
3. 定义一个发邮件的函数
如下。传入邮件标题和内容,执行发送任务,返回发送结果。
1 | # 定义一个邮件发送函数,传入邮件标题和内容,执行发送任务,返回发送结果 |
4. 主函数
主函数的功能比较少,主要就是整合前面两个部分的内容,先运行指令,查询服务器状态,之后调用发邮件的函数,完成服务器状态上报。
一般来说,只要服务器正常运行,网络连接没有问题,那么上报消息就能够正常发送到指定的邮箱。这样,即使我们不在实验室,也可以通过上报邮件实时监测服务器状态;此外,对于服务器正常运行但ssh登陆不上的情况,我们同样可以根据上报邮件的内容,进行问题排查
1 | def run(): |
三、通过crontab设置定时任务
参考往期博客文章《Linux服务器维护零碎知识点整理 》 。
如下图,我们编辑 /etc/crontab
文件,添加下面的几行内容,即可实现任务定时运行(下图中 repo_status_by_email.py
脚本会在早上9点整和下午3点20分各运行一次;如果需要更高频次的监测,可以修改前面的时间,把hour对应的那一列改为通配符 *
)。
四、成品展示
自动发送的邮件内容大致如下:
要想监测服务器上更多的内容,可以修改 check_machine_status()
,添加更多需要执行的指令。
以上。