Python|实现NBU自动巡检

在《Kettle|自助巡检》中,我曾利用ETL工具实现了除数据库备份检查之外的每日巡检工作,这一篇聊聊NBU备份巡检自动化。

分析过程

公司数据库涉及Oracle和SQL server,对于每日数据库巡检来说,Oracle数据库都是通过bplist语句进行查询,SQL server则是通过NetBackup客户端进行点击查询。
最好SQL server也能通过语句查询,这样整个方案就显得更合理。后来在网上看到这篇文章《Netbackup命令之bplist》,终于知道SQL server也可以通过bplist语句进行备份查询。
实现过程就比较顺利了:

读取待巡检数据库清单

通过sqlite数据库,记录数据库巡检清单信息表,涉及数据库服务器名、服务器IP、数据库类型、数据库用途、负责人邮箱等信息。

逐一查询数据库备份情况

遍历数据库巡检清单,逐一进行bplist查询。

  1. 通过loguru记录每一步查询日志,并记录到log文件中。
  2. 在sqlite中建立巡检信息表,将查询结果插入到表中,利于后续查询分析使用。
  3. 每日轮询,查询区间为轮询日的前一自然日。

判断备份是否正常

根据bplist查询语句返回的结果判断备份是由正常。根据分析,若返回结果包含“- -rw- - -”则表明备份正常,若结果包含“EXIT STATUS” / null 则表明查询区间NBU无备份信息。

邮件通知

将查询结果通知数据库负责人,为提高阅读性,正文采用html格式。

定时执行

将写好的python脚本添加到bat文件中,通过服务器的计划任务程序定时执行bat即可。

功能源码

代码部分

os部分

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
import os 
from loguru import logger
import datetime
import sqlite3
import resultEmail

# 创建日志对象
FileLog = 'log{}.log'.format(datetime.date.today())
logger.add(FileLog,rotation="500MB", encoding="utf-8", enqueue=True)

# 获取昨天日期
def getYesterday():
today = datetime.date.today()
oneday = datetime.timedelta(days=1)
yesterday = today - oneday
return yesterday.strftime(r'%Y-%m-%d')

# 查询系统清单
def QuerySystemInfo(yesterday):
conn = sqlite3.connect(r'D:\sqlite\********') # sqlite文件
c = conn.cursor()
# 查询系统清单,逐行进行备份检查
querySql = c.execute("select * from bd_dbsysteminfo order by email")
logger.info('#######待巡检数据库清单查询完成#######')
for row in querySql:
systemnameList.append(row[1])
systemtypeList.append(row[3])
conn.close()

# 查询备份情况
def CmdQuery(systemname,systemtype,yesterday):
logger.info('#######数据库备份巡检#######')
if systemtype == 'Oracle':
Query = r'cd C:\Program Files\Veritas\NetBackup\bin\ && bplist -C {} -S nbu5230 -s {} -e {} -t 4 -l -R /'.format(systemname,yesterday,yesterday)
elif systemtype == 'SqlServer':
Query = r'cd C:\Program Files\Veritas\NetBackup\bin\ && bplist -C {} -S nbu5230 -s {} -e {} -t 15 -l -R /'.format(systemname,yesterday,yesterday)
else :
logger.error('+++++++数据库{},数据库类型{}有误+++++++'.format(systemname,systemtype))
details = os.popen(Query).read()
line = details.split('\n')
# cd C:\Program Files\Veritas\NetBackup\bin\&&bplist -C USERMIC-6E73OBR -S nbu5230 -s 2023-03-01 -e 2023-03-10 -t 4 -l -R /
if 'EXIT STATUS 227' in details:
logger.error('+++++++数据库{},数据库类型{}在{}未查到备份文件+++++++'.format(systemname,systemtype,yesterday))
InsertDatabase(systemname,yesterday,details,'无备份')
elif ('-rw---' in details) or len(line)>=5 :
logger.info('#######数据库{},数据库类型{}在{}存在备份文件#######'.format(systemname,systemtype,yesterday))
InsertDatabase(systemname,yesterday,details,'正常')
else :
logger.error('+++++++数据库{},数据库类型{}在{}查询结果异常+++++++'.format(systemname,systemtype,yesterday))
InsertDatabase(systemname,yesterday,details,'无备份')

# 插入巡查信息记录表
def InsertDatabase(systemname,querydate,details,result):
insertContent = (systemname,querydate,details,result)
conn = sqlite3.connect(r'D:\sqlite\JicAiDatabase')
c = conn.cursor()
querySql = c.execute("insert into system_nbubakupinfo (systemname,querydate,details,result) values (?,?,?,?)",insertContent)
conn.commit()
conn.close()
logger.info('#######{}日,服务器{}的NBU备份日志已插入数据库#######'.format(querydate,systemname))

if __name__ == '__main__':
yesterday = getYesterday()
systemnameList = []
systemtypeList = []
logger.info('#######巡检开始#######')
QuerySystemInfo(yesterday)
for i in range(0,len(systemnameList)):
CmdQuery(systemnameList[i],systemtypeList[i],yesterday)
logger.info('***开始发送邮件***')
resultEmail.sendEmail(yesterday)
logger.info('***邮件已发给各系统管理员***')
resultEmail.toManager(yesterday)
logger.info('***邮件已发给NBU管理员***')
logger.info('***邮件发送完成***')
logger.info('#######巡检结束#######')

email部分

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
import datetime
import sqlite3
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header

def sendEmail(yesterday):
toEmail = []
contents = []
details = []
subject = '{}-数据库备份巡检结果通知'.format(datetime.date.today().strftime(r'%Y%m%d'))
conn = sqlite3.connect(r'D:\sqlite\******')
c = conn.cursor()
querySql = c.execute("select distinct email from bd_dbsysteminfo order by email")
for row in querySql:
toEmail.append(row[0])
for row in toEmail:
table = ''
detail = 'details:'
contentSql = c.execute("select a.systemname,b.systemip,b.systemmemo,a.result,a.details from system_nbubakupinfo a left join bd_dbsysteminfo b on a.systemname=b.systemname where b.email='{}' and a.querydate='{}'".format(row,yesterday))
for i in contentSql:
# 封装内容
detail = detail + i[4]
if i[3] == '正常' :
table = table + r'<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>'.format(i[0],i[1],i[2],i[3])
else :
table = table + r'<tr><td>{}</td><td>{}</td><td>{}</td><td style="color:red;">{}</td></tr>'.format(i[0],i[1],i[2],i[3])
contents.append(r'<p>{}日数据库备份巡检结果</p><table border="1"><tbody><tr><th style="text-align:center;">服务器名</th><th style="text-align:center;">服务器IP</th><th style="text-align:center;">数据库用途</th><th style="text-align:center;">巡检结果</th></tr>{}</tbody><colgroup><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"></colgroup></table><span>详细备份信息参见附件!该邮件为系统自动发送,请勿回复。</span>'.format(yesterday,table))
details.append(detail)
conn.close()

for i in range(0,len(toEmail)):
# 创建 SMTP 对象
smtp = smtplib.SMTP()
smtp.connect("****.cn", port=25)
smtp.login(user="**@*.cn", password=r"***")
message = MIMEMultipart()
message['From'] = Header("***@***.cn", 'utf-8')
message['Subject'] = Header(subject, 'utf-8')
with open('details.txt','w') as f:
f.write(details[i])
message['To'] = Header(toEmail[i], 'utf-8')
message.attach(MIMEText(contents[i], 'html', 'utf-8'))
att = MIMEText(open('details.txt','rb').read(),'base64','utf-8')
att['Content-Type'] = 'application/octet-stream'
att["Content-Disposition"] = 'attachment; filename="details.txt"'
message.attach(att)
smtp.sendmail(from_addr="******@****.cn", to_addrs=toEmail[i], msg=message.as_string())
smtp.quit()

def toManager(yesterday):
to = ''
contents = ''
subject = '{}-数据库备份巡检结果通知'.format(datetime.date.today().strftime(r'%Y%m%d'))
conn = sqlite3.connect(r'D:\sqlite\****')
c = conn.cursor()
querySql = c.execute("select distinct supermanager from bd_dbsysteminfo ")
for row in querySql:
to = row[0]
table = ''
contentSql = c.execute("select a.systemname,b.systemip,b.systemmemo,a.result from system_nbubakupinfo a left join bd_dbsysteminfo b on a.systemname=b.systemname where a.querydate='{}'".format(yesterday))
for i in contentSql:
if i[3] == '正常' :
table = table + r'<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>'.format(i[0],i[1],i[2],i[3])
else :
table = table + r'<tr><td>{}</td><td>{}</td><td>{}</td><td style="color:red;">{}</td></tr>'.format(i[0],i[1],i[2],i[3])
contents = contents + '<p>{}日数据库备份巡检结果</p><table border="1"><tbody><tr><th style="text-align:center;">服务器名</th><th style="text-align:center;">服务器IP</th><th style="text-align:center;">数据库用途</th><th style="text-align:center;">巡检结果</th></tr>{}</tbody><colgroup><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"></colgroup></table><span>该邮件为系统自动发送,请勿回复。</span>'.format(yesterday,table)
conn.close()

smtp = smtplib.SMTP()
smtp.connect("****.****.cn", port=25)
smtp.login(user="****@***.cn", password=r"***")
message = MIMEMultipart()
message['From'] = Header("***@***.cn", 'utf-8')
message['Subject'] = Header(subject, 'utf-8')
message['To'] = Header(to, 'utf-8')
message.attach(MIMEText(contents, 'html', 'utf-8'))
smtp.sendmail(from_addr="***@***.cn", to_addrs=to, msg=message.as_string())
smtp.quit()

定时任务

1
2
3
4
5
@echo off
D:
cd D:\***
python ***.py
exit

总结

简单好用,轻轻松松。


商业转载请联系作者获得授权,非商业转载请注明出处。

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

Python|实现NBU自动巡检
http://hncd1024.github.io/2023/04/09/Python_NBU5230/
作者
CHEN DI
发布于
2023-04-09
许可协议