本文转载自微信公众号「新钛云服」,作者徐磊。转载本文请联系新钛云服公众号。
在日常运维中,当你遇到每天邮件发出当天服务器的监控状态等这些类似需求时,你还在每天下午快下班的时候打开zabbix截图、发邮件......日复一日的手动处理吗?如果是,这篇干货将为您解放双手。
文档说明
本文档主要介绍利用python脚本,指定主机名,自动获取zabbix监控图,下载到本地,形成word文档。
总体思路:先通过zabbix API获取auth;通过主机名获取host ID;通过host ID获取graph ID;再利用爬虫代码将图片下载到本地;通过python的docx 模块插入至word文档(本文zabbix的版本是5.0,python是3.8)。
一、自动获取zabbix监控图保存至本地
首先,获取zabbix的auth ID,通过zabbix API获取主机id,graph ID等信息。打印出auth ID之后,保存下来,之后获取host ID需要用到:
- #获取authkey
- ZABBIX_URL = 'https://www.zabbix.cn'
- ZABBIX_USERNAME = "user"
- ZABBIX_PASSWORD = "password"
- url = "{}/api_jsonrpc.php".format(ZABBIX_URL)
- header = {"Content-Type": "application/json"}
- # auth user and password
- data = {
- "jsonrpc": "2.0",
- "method": "user.login",
- "params": {
- "user": ZABBIX_USERNAME,
- "password": ZABBIX_PASSWORD
- },
- "id": 1,
- }
- # 由于API接收的是json字符串,故需要转化一下
- value = json.dumps(data).encode('utf-8')
- # 对请求进行包装
- req = request.Request(url, headers=header, data=value)
- # 验证并获取Auth ID
- try:
- # 打开包装过的url
- result = request.urlopen(req)
- except Exception as e:
- print("Auth Failed, Please Check Your Name And Password:", e)
- else:
- response = result.read()
- # 上面获取的是bytes类型数据,故需要decode转化成字符串
- page = response.decode('utf-8')
- # 将此json字符串转化为python字典
- page = json.loads(page)
- result.close()
- print("Auth Successful. The Auth ID Is: {}".format(page.get('result')))
变量hostname即是需要查询的主机名,通过主机名查询到host ID。当然也可以使用input函数做交互,实现动态查询。
- #获取hostid
- data = {
- "jsonrpc": "2.0",
- "method": "host.get",
- "params": {
- "output": [
- "hostid",
- "host"
- ],
- "selectInterfaces": [
- "interfaceid",
- "ip"
- ]
- },
- "auth": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX", #这里的auth的值就是上文获取到的auth
- "id": 2
- }
- r = requests.post(url, headers=header, data=json.dumps(data))
- hostname = abc123
- with open(hostname_txt,'r') as f:
- tmp_list = [x.strip("\n") for x in f.readlines()]
- for hostname in tmp_list:
- if r.json().get('result'):
- for i in r.json()['result']:
- if i['host'] == hostname:
- hostids = i['hostid']
使用host ID查询到graph ID,并保存到本地;
value传入的值,from和to这两个key决定了获取监控图的监控时间段,本例设置的是一个月;
value中"profileIdx": "web.graphics.filter"是zabbix 5.0 API的新特性,如果不传入,获取的监控时段是一个小时且无法更改。
- #获取graphid列表和字典
- class ZabbixGraph(object):
- def __init__(self,url,name,password):
- self.url=url
- self.name=name
- self.password=password
- #初始化的时候生成cookies
- cookiejar = http.cookiejar.CookieJar()
- #cookiejar = cookielib.CookieJar()
- urlOpener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar))
- #urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
- values = {"name":self.name,'password':self.password,'autologin':1,"enter":'Sign in'}
- data = parse.urlencode(values).encode("utf-8")
- #data = urllib.urlencode(values)
- request = urllib.request.Request(url, data)
- try:
- urlOpener.open(request,timeout=10)
- self.urlOpener=urlOpener
- except ValueError:
- print("网页打开失败")
- def GetGraph(self,url,values,p_w_picpath_dir):
- key=values.keys()
- print(values)#显示最底下value传入的值
- if "graphid" not in key:
- print("请确认是否输入graphid")
- sys.exit(1)
- #以下if 是给定默认值
- if "period" not in key:
- #默认获取一天的数据,单位为秒
- values["period"]=2626560
- if "stime" not in key:
- #默认为当前时间开始
- values["stime"]=datetime.datetime.now().strftime('%Y%m%d%H%M%S')
- if "width" not in key:
- values["width"]=800
- if "height" not in key:
- values["height"]=200
- data=parse.urlencode(values).encode("utf-8")
- #data=urllib.urlencode(values)
- request = urllib.request.Request(url,data)
- url = self.urlOpener.open(request)
- p_w_picpath = url.read()
- p_w_picpathname="%s/%s.png" % (p_w_picpath_dir, values["hostname"]+"_images"+values["name"])
- f=open(p_w_picpathname,'wb+')
- f.write(p_w_picpath)
- f.close()
- graph_id_data = {
- "jsonrpc": "2.0",
- "method": "graph.get",
- "params": {
- "output": "extend",
- "hostids": hostids,
- "sortfield": "name"},
- "auth": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
- "id": 1}
- graph_data = requests.post(url, headers=header, data=json.dumps(graph_id_data))
- graph_list_x = []
- graph_dict_name = {}
- if graph_data.json().get('result'):
- for i in graph_data.json()['result']:
- graph_id = i['graphid']
- graph_name_x = i['name']
- graph_name=graph_name_x.replace("/","_")
- graph_dict_name[graph_id]=graph_name
- graph_list_x.append(graph_id)
- #==========================================================
- #此url是获取图片是的,请注意饼图的URL 和此URL不一样,请仔细观察!
- gr_url="https://www.zabbix.cn/chart2.php"
- #登陆URL
- indexURL="https://www.zabbix.cn/index.php"
- username="user"
- password="password"
- #用于图片存放的目录
- p_w_picpath_dir="/picture"
- #图片的参数,该字典至少传入graphid。
- for key, value in graph_dict_name.items():
- values = {"graphid":key,"name":value,"hostname":hostname,"width":800,"height":200,"from":"now-30d","to":"now","profileIdx": "web.graphics.filter"}
- b=ZabbixGraph(indexURL,username,password)
- b.GetGraph(gr_url,values,p_w_picpath_dir)
二、将图片编辑到word,并根据graph name命名
写入word:
- from docx import Document
- from docx.shared import Inches
- import os
- from PIL import Image
- # 要插入的图片所在的文件夹
- pwd = os.getcwd()
- fold='picture'
- fold_DS = fold + '/' + '.DS_Store'
- word = pwd + "/" + "word文档"
- try:
- os.mkdir(pwd+'/'+fold,755)
- except:
- print("目录已存在!无须创建")
- # os.walk(fold)没有返回值,所以这么做显然没有结果,是错的
- # pics=list(os.walk(fold)[3])
- # # pics.pop()
- # print(pics)
- # pics是图片的名字
- # root是string类型, dirs和pics是list类型
- try:
- os.remove(fold_DS)
- except:
- print("no .DS_Store文件")
- for root, dirs, pics in os.walk(fold):
- doc=Document()
- for i in range(0,len(pics)):
- filepath = root + '/' + str(pics[i])
- string = str(pics[i].strip(".png"))
- #print(string)
- try:
- doc.add_paragraph(string)
- doc.add_picture(filepath,width=Inches(6),height=Inches(3))
- except Exception:
- pic_tmp=Image.open(filepath)
- # 如果格式有问题,就用save转换成默认的jpg格式
- pic_tmp.save(pic_tmp)
- # 把处理后的图片放进Document变量doc中
- doc.add_picture(filepath, width=Inches(6),height=Inches(3))
- # 把Document变量doc保存到指定路径的docx文件中
- doc.save(word)
- #输出保存成功的标志
- print("pic", string, "successfully added.")
三、python模块
本次使用到的模块,在运行之前检查主机是否安装本次执行需要的模块。
一般需要单独安装的模块有四个urllib3,requests,Pillow,python-docx。
- import json
- import requests
- from urllib import request, parse
- from urllib.request import urlopen
- import sys
- import datetime
- import urllib.request
- import http.cookiejar
- import os
- import ssl
- from docx import Document
- from docx.shared import Inches
四、注意事项
如果有些同学的zabbix使用的是https的访问方式,在代理里需要跳过证书验证。
ssl._create_default_https_context = ssl._create_unverified_context
在获取到的图片打开的时候提示文件已损坏,使用其他代码编辑器打开查看代码,发现是登陆失败的问题,需要检查登陆账户和方式是否正确。