zabbix 二次开发之报表系统
最近业务部门踢需求说想看分别KVM和Mysql集群的这批设备的一些周平均统计信息,如Load、Mem、IOPS等这些指标,正好加上这段时间考虑的zabbix功能拆分,于是有了本文。
实现架构
- bootstrap 前端
- tornado 后端
- monogodb 数据库
为啥这么来玩?
- 现有zabbix系统进行了大量的二次开发,做新功能、bug修复、维护均是大麻烦
- 现在zabbix是基于1.8二次开发的,一直在筹划版本的升级工作,再加新功能得不偿失
- 报表功能从监控的角度的来说,集中在一起坐未必是一个好的选择,那为何不独立出来呢?
- tornado + bootstrap + monogodb的组合,可以快速的进行业务需求的扩展,之后的所有的报表需求均在该系统上进行统一维护
功能拆分
业务部门提的需求还是比较简单的,就是根据模块管理或者给定的IP列表,定时生存统计报表,然后以附件的形式发邮件给指定的收件人。所以我们就大概分如下几个部门:
-
前端web,用来维护IP列表、统计指标、关联模版这些的业务需求
-
后台功能
- 写入xls,没玩过,需要查下资料
- 发件部分,唯一麻烦的是需要搞下怎么发送附件
- 日志记录
-
定时执行,这部分其实可以分为两种,一种是临时性的查看,就需要在前端有按钮触发执行的动作,另外就是周期性的,挂crontab好了
- …
我暂时考虑的就这么多了,由于时间非常有限(1~2天),所以这些功能未必全做,但该有的我们脑海中还是要有的,要记住我们要的是工具、产品,而不是一次性的脚本!
环境搭建
这部分没啥说的,都是网上资料一搜一大把的玩意。分别需要依赖的东西有:
* python2.6+
* pip
* xlwt
* MySQLdb
* tornado
* bootstrap
* jquery
* monogodb
前端web实现
其实前端web是整个过程中最不用着急去做的,因为现阶段能做的就是一个非常简单的交互,不会有太复杂的业务逻辑在里面。凡事都是先跑起来再优化嘛,所以重点还是后台的功能。
直接看下面的效果图吧,markdown直接插入html代码会有点问题,这部分的实现参考之前的tornado+bootsharp入门。
实现功能
在web前端的文本框输入IP列表的话,则会后台写入ips.txt,ips.txt是后台的报表脚本用来自动获取数据的IP列表文件。
主程序report.py:
import os.path
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8888, help="run on the given port", type=int)
ips_file = 'ips.txt'
class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
def post(self):
ips_list = self.get_argument('ips')
ips_list = ips_list.split('\r\n')
ips_hander = open(ips_file,'w+')
for ip in ips_list:
ips_hander.seek(0,2)
ips_hander.write(ip.strip()+ os.linesep)
ips_hander.close()
self.write('success!')
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application([(r"/",LoginHandler),],
template_path = os.path.join(os.path.dirname(__file__),"templates"),
static_path =os.path.join(os.path.dirname(__file__), "static"),
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
效果图
不足
- 时间太短,只实现了累加,无修改、查询、删除等功能
- 无其他的业务指标的修改支持
后台统计脚本
这部分是比较大头的,实现思路也很简单,分别从ips.txt、items.txt中遍历IP、需要统计的数据,去查询mysql数据库即可,随后使用xlwt库将结果写入xls文件、调用send_mail发邮件出去。
上代码吧:
KVM_report.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import MySQLdb
import time
import xlwt
import os
from mail import send_mail_att
from mail import HtmlContent
#mysql configure
host='1.2.3.4'
user='user'
passwd='passwd'
port = 3306
path = '/var/www/html/report/'
#configure file ips_file = 'ips.txt'
items_file = 'items.txt'
ips_file = 'ips.txt'
items = open(path + items_file)
items_list = items.readlines()
ips = open(path + ips_file)
ips_list = ips.readlines()
#get unix time
now = int(time.time())
week_ago = int(time.time() - 7 * 24 * 60 *60)
#avg,max,min
value_types = ['value_max','value_avg','value_min']
#write to excel
file = xlwt.Workbook()
table = file.add_sheet('KVM')
#write the title
table.write(0,0,'IP')
table.write(0,1,u'CPU利用率(mim)')
table.write(0,2,u'CPU利用率(avg)')
table.write(0,3,u'CPU利用率(max)')
table.write(0,4,u'负载(max)')
table.write(0,5,u'负载(avg)')
table.write(0,6,u'负载(min)')
table.write(0,7,u'内存使用率(max)')
table.write(0,8,u'内存使用率(avg)')
table.write(0,9,u'内存使用率(min)')
table.write(0,10,u'/letv分区使用率(max)')
table.write(0,11,u'/letv分区使用率(avg)')
table.write(0,12,u'/letv分区使用率(min)')
table.write(0,13,u'swap使用率(max)')
table.write(0,14,u'swap使用率(avg)')
table.write(0,15,u'swap使用率(min)')
row = 1
col = 1
try:
conn=MySQLdb.connect(host=host,user=user,passwd=passwd,port=port)
cur=conn.cursor()
conn.select_db('zabbix')
cur.execute('set names utf8')
for ip in ips_list:
for item in items_list:
for value_type in value_types:
sql = '''select AVG(t.%s) from hosts h,items i,trends t where h.ip='%s' and h.hostid=i.hostid and i.key_='%s' and i.itemid=t.itemid AND clock BETWEEN %s AND %s ;''' %(value_type.strip('\n'),ip.strip('\n'),item.strip('\n'),week_ago,now)
result=cur.execute(sql)
result=cur.fetchone()
#print item
try:
if(item.strip('\n') == 'system.cpu.util[,idle,avg1]' ):
res = 100 - result[0]
else:
res = result[0]
res=round(res,2)
except TypeError:
continue
table.write(row,col,res)
#back to the begin
col = col + 1
if(col > 15):
col = 1
table.write(row,0,ip);
row = row + 1
cur.close()
conn.close()
except MySQLdb.Error,e:
print "Mysql Error %d: %s" % (e.args[0], e.args[1])
att_file='KVM-'+time.strftime('%Y-%m-%d-%H-%M',time.localtime(time.time()))+'.xls'
file.save(path + att_file)
#send mail to mail_list
mail_list=["huangsicong@letv.com","ruifengyun@letv.com"]
for mail in mail_list:
content = HtmlContent('KVM虚拟机报告,详见附件','');
send_mail_att(mail,'KVM虚拟机周报',content,path + att_file)
简要说明
- Mysql这部分的取数据没啥说的,唯一需要注意的是对于业务部门来说可能很简单的就是要某个指标的例如load的周平均值,但实际上对应的这个item在zabbix的后台Mysql数据库中可能是存在了trends_uint表中,而不是trends表的,所以如果你去没有事前确定好item的取值类型,那查错了数据库,结果肯定是空的。
- xlwt是一个神器,很好用,我用的比较简单,就是循环取数然后写进去,大家有这方面的xls读写的话可以考虑xlwt比xlrd好用
-
关于path变量,由于最终这个脚步是要放到crontab执行的,所以path还是需要配置下的,不然直接扔进去会有问题的,ips.txt这种的配置文件,系统肯定是找不到的
-
发邮件我是自己参考网上的一些个脚步自己封装了下,其实我就是炒芮峰云的,哈哈。我就说两点
-
对于个人邮箱,必须登录,否则验证会失败,而对应一些公司公共的邮件帐号如auotreport这种的就不能登录,否则会验证失败,我这边是如此,仅供参考吧,大家最好看下公司的IT部门是怎么配置的。
-
设置MIMEText的时候必须设置为html格式,也就是说必须把邮件正文(content)扔html里面去,不然会被公司邮件服务器或者其他邮件服务器当作垃圾邮件的。。
-
body = MIMEText(content,_subtype='html',_charset='utf8')
定时执行
这部分我弄得很简单的,前端现在没做手动触发执行的逻辑,对于crontab则是写脚本的时候多考虑下path的问题就解决了。
后记
日志功能暂时也没时间做了,其实这个我觉得是非常有必要的。好的一个工具应该自己去记录自己的执行日志、报错日志,而不能指望系统或者异常给你爆出来,那就晚了。
不足的地方有很多:
- 配置文件直接写文件的形式,不够优雅,维护起来也麻烦,后续可以改成mongodb存储
- 时间有限,前台没做啥cookie验证,只是临时性的一个东西,能用就好,远对不起报表系统这么牛逼的名字
- 日志模块也没做
- 很多的逻辑都没做,没办法,领导不给时间搞呀。。