├── .fuse_hidden000012f500000001 ├── .idea ├── encodings.xml ├── misc.xml ├── modules.xml ├── weixin.iml └── workspace.xml ├── QQ20170425141712.png ├── README.md ├── Screenshot_2017-01-10-18-06-11.png ├── Screenshot_2017-01-10-18-07-06.png ├── conf ├── BLog.py ├── INIFILES.py ├── __init__.py └── file_util.py ├── config.ini ├── get_pic.py ├── ghostdriver.log ├── problem.xml ├── recover.xml ├── requests ├── Pillow-4.0.0-cp27-cp27m-manylinux1_x86_64.whl ├── fontconfig-2.10.95-10.el7.x86_64.rpm ├── freetype-2.4.11-12.el7.x86_64.rpm ├── phantomjs-2.1.1-linux-x86_64.tar.bz2 ├── requests-2.12.4-py2.py3-none-any.whl ├── requests-2.12.4.tar.gz └── selenium-3.0.2.tar.gz ├── requirements.txt ├── test_xml.py ├── weixin.jpg ├── weixin.py └── weixin_bak.py /.fuse_hidden000012f500000001: -------------------------------------------------------------------------------- 1 | [INFO - 2017-01-09T18:46:22.534Z] GhostDriver - Main - running on port 50482 2 | [INFO - 2017-01-09T18:46:23.441Z] Session [eb1f97d0-d69b-11e6-90a5-dbb5d5b2099d] - page.settings - {"XSSAuditingEnabled":false,"javascriptCanCloseWindows":true,"javascriptCanOpenWindows":true,"javascriptEnabled":true,"loadImages":true,"localToRemoteUrlAccessEnabled":false,"userAgent":"Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1","webSecurityEnabled":true} 3 | [INFO - 2017-01-09T18:46:23.441Z] Session [eb1f97d0-d69b-11e6-90a5-dbb5d5b2099d] - page.customHeaders: - {} 4 | [INFO - 2017-01-09T18:46:23.441Z] Session [eb1f97d0-d69b-11e6-90a5-dbb5d5b2099d] - Session.negotiatedCapabilities - {"browserName":"phantomjs","version":"2.1.1","driverName":"ghostdriver","driverVersion":"1.2.0","platform":"linux-unknown-64bit","javascriptEnabled":true,"takesScreenshot":true,"handlesAlerts":false,"databaseEnabled":false,"locationContextEnabled":false,"applicationCacheEnabled":false,"browserConnectionEnabled":false,"cssSelectorsEnabled":true,"webStorageEnabled":false,"rotatable":false,"acceptSslCerts":false,"nativeEvents":true,"proxy":{"proxyType":"direct"}} 5 | [INFO - 2017-01-09T18:46:23.441Z] SessionManagerReqHand - _postNewSessionCommand - New Session Created: eb1f97d0-d69b-11e6-90a5-dbb5d5b2099d 6 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/weixin.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 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 | 1483953404466 39 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /QQ20170425141712.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/QQ20170425141712.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ZABBIX可以实现短信、邮件、微信等各种报警,这三种基本大家都很熟悉, 现在基于微信写py,之前写了个无图的,感觉微信色彩不丰富,再加个有图的,说可以实现微信报警,苍老师的话牢记心头:Life is short,you need python! 2 | 3 | [TOC] 4 | ### 1 微信配置(与无图版一样) 5 | 微信公众号官网:https://qy.weixin.qq.com/ 6 | 我们主要获取四个参数:部门id,应用ID和CorpID和CorpSecret 7 | #### 1.1 注册安装 8 | 注册微信企业号,安装手机微信略过 9 | ##### 1.1.1 部门设置 10 | 在通信录管理里面设置部门,如下图,我们这里设置的运维部,这个部门id要记住,在ZABBIX里面要配置这个名称,然后把你需要发送告警的人员添加到这个部门里面 11 | ##### 1.1.2 应用设置 12 | 点击左侧“应用中心”,新建消息型应用,应用名称为“服务器报警”,“应用可见范围”,添加刚刚新建的子部门(运维部),点击“服务器报警”,记录应用ID 13 | ##### 1.1.3 权限管理 14 | 点击左侧“设置”,权限管理,新建普通管理组,名称填写“服务器报警组”。点击修改“通讯录权限”,勾选管理,点击修改“应用权限”,勾选刚刚创建的“服务器报警”,点击刚刚创建的“服务器报警组”,记录左侧的CorpID与CorpSecret 15 | ### 2 程序配置 16 | 代码托管到github:https://github.com/bluetom520/zabbix-weixin-picture 17 | 下载 18 | ``` 19 | git clone https://github.com/bluetom520/zabbix-weixin-picture.git 20 | ``` 21 | 依赖包 22 | ``` 23 | image==1.5.5 24 | lxml==3.5.0 25 | selenium==3.0.2 26 | ``` 27 | 安装phantomjs 28 | ``` 29 | tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2 30 | mv phantomjs-2.1.1-linux-x86_64 /usr/local/phantomjs-2.1.1 31 | ``` 32 | 程序部署 33 | ``` 34 | cp zabbix-weixin-picture/* /usr/lib/zabbix/alertscripts/ 35 | cd /usr/lib/zabbix/alertscripts/ 36 | chown -R zabbix:zabbix pic 37 | chown -R zabbix:zabbix weixin.py 38 | chmod o+x weixin.py 39 | chown -R zabbix:zabbix config.ini 40 | chmod o+w config.ini 41 | ``` 42 | 修改config.ini,把上节获得的三个参数填入,web 设置为zabbix服务器主页,是点击报警信息后跳转的页面,设置的监控数据的最新出图。 43 | ``` 44 | [wei] 45 | corpid = wx3317042c8bcf7551 46 | corpsecret = m0VqePgfDsTbVoFlGSx5-JOCbE5p43rf5G-GC2CqN4Wq2Ce0OJQkgo0JnXMqKypv 47 | agentid = 2 48 | toparty = 49 | web = http://192.168.1.199/zabbix/ 50 | ``` 51 | ### 3 ZABBIX配置 52 | #### 3.1 报警媒介类型 53 | 到管理-》报警媒介类型配置我们的微信 54 | ![](leanote://file/getImage?fileId=587386aa4f1ffe4e59000001) 55 | #### 3.2 配置用户 56 | 到管理-》用户-》报警媒介-》添加,注意填写收件人为我们之前设置的运维部id 2 57 | ![](leanote://file/getImage?fileId=587386cf4f1ffe4e59000002) 58 | #### 3.3 动作设置 59 | 到配置-》动作-》创建动作(触发器) 60 | - 动作 61 | ![](leanote://file/getImage?fileId=587089ffd31d9c3103000006) 62 | 63 | - 条件 64 | ![](leanote://file/getImage?fileId=58708a1dd31d9c3103000007) 65 | - 操作 66 | ![](leanote://file/getImage?fileId=587386fb4f1ffe4e59000003) 67 | 68 | ### 4 效果展现 69 | 故障图 70 | ![](leanote://file/getImage?fileId=5874b25d2eb3ec5799000005) 71 | 恢复图 72 | ![](leanote://file/getImage?fileId=5874b2292eb3ec5799000004) 73 | 74 | ### 5 docker环境修改 75 | > * 参照无图版 76 | 77 | 78 | ### 如果你觉得微信报警对你有帮助, 可以对作者进行小额捐款(微信) 79 | 80 | ![weixin](weixin.jpg) 81 | 82 | -------------------------------------------------------------------------------- /Screenshot_2017-01-10-18-06-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/Screenshot_2017-01-10-18-06-11.png -------------------------------------------------------------------------------- /Screenshot_2017-01-10-18-07-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/Screenshot_2017-01-10-18-07-06.png -------------------------------------------------------------------------------- /conf/BLog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = 'bluetom' 4 | 5 | import sys 6 | import logging 7 | from logging.handlers import RotatingFileHandler 8 | import os 9 | 10 | #{{{class ColoredFormatter 11 | class ColoredFormatter(logging.Formatter): 12 | '''A colorful formatter.''' 13 | 14 | def __init__(self, fmt = None, datefmt = None): 15 | logging.Formatter.__init__(self, fmt, datefmt) 16 | # Color escape string 17 | COLOR_RED='\033[1;31m' 18 | COLOR_GREEN='\033[1;32m' 19 | COLOR_YELLOW='\033[1;33m' 20 | COLOR_BLUE='\033[1;34m' 21 | COLOR_PURPLE='\033[1;35m' 22 | COLOR_CYAN='\033[1;36m' 23 | COLOR_GRAY='\033[1;37m' 24 | COLOR_WHITE='\033[1;38m' 25 | COLOR_RESET='\033[1;0m' 26 | 27 | # Define log color 28 | self.LOG_COLORS = { 29 | 'DEBUG': '%s', 30 | 'INFO': COLOR_GREEN + '%s' + COLOR_RESET, 31 | 'WARNING': COLOR_YELLOW + '%s' + COLOR_RESET, 32 | 'ERROR': COLOR_RED + '%s' + COLOR_RESET, 33 | 'CRITICAL': COLOR_RED + '%s' + COLOR_RESET, 34 | 'EXCEPTION': COLOR_RED + '%s' + COLOR_RESET, 35 | } 36 | 37 | def format(self, record): 38 | level_name = record.levelname 39 | msg = logging.Formatter.format(self, record) 40 | 41 | return self.LOG_COLORS.get(level_name, '%s') % msg 42 | #}}} 43 | #{{{class Log 44 | class Log(object): 45 | 46 | ''' 47 | log 48 | ''' 49 | def __init__(self, filename, level="debug", logid="qiueer", mbs=20, count=10, is_console=True): 50 | ''' 51 | mbs: how many MB 52 | count: the count of remain 53 | ''' 54 | try: 55 | self._level = level 56 | #print "init,level:",level,"\t","get_map_level:",self._level 57 | self._filename = filename 58 | self._logid = logid 59 | 60 | self._logger = logging.getLogger(self._logid) 61 | file_path = os.path.split(self._filename)[0] 62 | if not os.path.exists(file_path): 63 | os.makedirs(file_path) 64 | 65 | if not len(self._logger.handlers): 66 | self._logger.setLevel(self.get_map_level(self._level)) 67 | 68 | fmt = '[%(asctime)s] %(levelname)s\n%(message)s' 69 | datefmt = '%Y-%m-%d %H:%M:%S' 70 | formatter = logging.Formatter(fmt, datefmt) 71 | 72 | maxBytes = int(mbs) * 1024 * 1024 73 | file_handler = RotatingFileHandler(self._filename, mode='a',maxBytes=maxBytes,backupCount=count) 74 | self._logger.setLevel(self.get_map_level(self._level)) 75 | file_handler.setFormatter(formatter) 76 | self._logger.addHandler(file_handler) 77 | 78 | if is_console == True: 79 | stream_handler = logging.StreamHandler(sys.stderr) 80 | console_formatter = ColoredFormatter(fmt, datefmt) 81 | stream_handler.setFormatter(console_formatter) 82 | self._logger.addHandler(stream_handler) 83 | 84 | except Exception as expt: 85 | print expt 86 | 87 | def tolog(self, msg, level=None): 88 | try: 89 | level = level if level else self._level 90 | level = str(level).lower() 91 | level = self.get_map_level(level) 92 | if level == logging.DEBUG: 93 | self._logger.debug(msg) 94 | if level == logging.INFO: 95 | self._logger.info(msg) 96 | if level == logging.WARN: 97 | self._logger.warn(msg) 98 | if level == logging.ERROR: 99 | self._logger.error(msg) 100 | if level == logging.CRITICAL: 101 | self._logger.critical(msg) 102 | except Exception as expt: 103 | print expt 104 | 105 | def debug(self,msg): 106 | self.tolog(msg, level="debug") 107 | 108 | def info(self,msg): 109 | self.tolog(msg, level="info") 110 | 111 | def warn(self,msg): 112 | self.tolog(msg, level="warn") 113 | 114 | def error(self,msg): 115 | self.tolog(msg, level="error") 116 | 117 | def critical(self,msg): 118 | self.tolog(msg, level="critical") 119 | 120 | def get_map_level(self,level="debug"): 121 | level = str(level).lower() 122 | #print "get_map_level:",level 123 | if level == "debug": 124 | return logging.DEBUG 125 | if level == "info": 126 | return logging.INFO 127 | if level == "warn": 128 | return logging.WARN 129 | if level == "error": 130 | return logging.ERROR 131 | if level == "critical": 132 | return logging.CRITICAL 133 | #}}} 134 | if __name__ == "__main__": 135 | from BLog import Log 136 | debug=False 137 | logpath = "/tmp/test.log" 138 | logger = Log(logpath,level="warn",is_console=True, mbs=5, count=5) 139 | 140 | 141 | logstr="helloworld" 142 | logger.error(logstr) 143 | logger.info(logstr) 144 | logger.warn(logstr) 145 | -------------------------------------------------------------------------------- /conf/INIFILES.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = 'TT' 4 | import sys,os,time 5 | import ConfigParser 6 | 7 | 8 | class Config: 9 | def __init__(self, path): 10 | self.path = path 11 | self.cf = ConfigParser.ConfigParser() 12 | self.cf.read(self.path) 13 | 14 | def get(self, field, key): 15 | result = "" 16 | try: 17 | result = self.cf.get(field, key) 18 | except: 19 | result = "" 20 | return result 21 | 22 | def set(self, field, key, value): 23 | try: 24 | self.cf.set(field, key, value) 25 | self.cf.write(open(self.path,'w')) 26 | except: 27 | return False 28 | return True 29 | 30 | 31 | def read_config(config_file_path, field, key): 32 | cf = ConfigParser.ConfigParser() 33 | try: 34 | cf.read(config_file_path) 35 | result = cf.get(field, key) 36 | except: 37 | sys.exit(1) 38 | return result 39 | 40 | 41 | def write_config(config_file_path, field, key, value): 42 | cf = ConfigParser.ConfigParser() 43 | try: 44 | cf.read(config_file_path) 45 | cf.set(field, key, value) 46 | cf.write(open(config_file_path,'w')) 47 | except: 48 | sys.exit(1) 49 | return True 50 | 51 | if __name__ == "__main__": 52 | config_file_path = 'config.ini' 53 | print read_config(config_file_path, 'baseconf', "host") 54 | 55 | write_config(config_file_path, 'baseconf', "host", '192.168.0.101') 56 | 57 | print read_config(config_file_path, 'baseconf', "host") -------------------------------------------------------------------------------- /conf/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = 'bluetom' -------------------------------------------------------------------------------- /conf/file_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = 'bluetom' 4 | 5 | """Package for operations. 6 | """ 7 | 8 | import os 9 | if __name__ == '__main__': 10 | import sys 11 | root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) 12 | sys.path.insert(0, root_path) 13 | 14 | import re 15 | import shlex 16 | 17 | import subprocess 18 | import sys 19 | import linecache 20 | reload(sys) 21 | sys.setdefaultencoding('utf8') 22 | 23 | # 需要修改,配置文件位置 24 | CONFIG_CFG = '/etc/zabbix/zabbix_agentd.conf' 25 | 26 | #{{{loadconfig 27 | 28 | 29 | def loadconfig(cfgfile=None, detail=False): 30 | """Read config file and parse config item to dict. 31 | """ 32 | if not cfgfile: 33 | cfgfile = CONFIG_CFG 34 | 35 | settings = {} 36 | with open(cfgfile) as f: 37 | for line_i, line in enumerate(f): 38 | # line_i[行号],line[每行内容] 39 | 40 | # 删除空白符(包括'\n', '\r', '\t', ' ') 41 | line = line.strip() 42 | 43 | # 跳过空行和注释('# '开头的) 44 | if not line or line.startswith('# '): 45 | continue 46 | 47 | # detect if it's commented 48 | if line.startswith('#'): 49 | line = line.strip('#') 50 | commented = True 51 | if not detail: 52 | continue 53 | else: 54 | commented = False 55 | 56 | # 将行以第一个'='分割 57 | ######################################### 58 | fs = re.split('=', line, 1) 59 | if len(fs) != 2: 60 | continue 61 | 62 | item = fs[0].strip() 63 | value = fs[1].strip() 64 | 65 | if settings.has_key(item): 66 | if detail: 67 | count = settings[item]['count'] + 1 68 | if not commented: 69 | settings[item] = detail and { 70 | 'file': cfgfile, 71 | 'line': line_i, 72 | 'value': value, 73 | 'commented': commented, 74 | } or value 75 | else: 76 | count = 1 77 | settings[item] = detail and { 78 | 'file': cfgfile, 79 | 'line': line_i, 80 | 'value': fs[1].strip(), 81 | 'commented': commented, 82 | } or value 83 | if detail: 84 | settings[item]['count'] = count 85 | 86 | return settings 87 | 88 | #}}} 89 | #{{{cfg_get 90 | 91 | 92 | def cfg_get(item, detail=False, config=None): 93 | """Get value of a config item. 94 | """ 95 | if not config: 96 | config = loadconfig(detail=detail) 97 | if config.has_key(item): 98 | return config[item] 99 | else: 100 | return None 101 | #}}} 102 | #{{{cfg_set 103 | 104 | 105 | def cfg_set(item, value, commented=False, config=None): 106 | """Set value of a config item. 107 | 如果可以获取到key,则对key后的item进行修改 108 | 如果获取不到key,则直接在配置文件后进行追加一行 109 | """ 110 | cfgfile = CONFIG_CFG 111 | v = cfg_get(item, detail=True, config=config) 112 | # print v 113 | 114 | if v: 115 | # detect if value change 116 | if v['commented'] == commented and v['value'] == value: 117 | return True 118 | 119 | # empty value should be commented 120 | # 如果有key,但是传的value值为空,会将此行进行注释 121 | if value == '': 122 | commented = True 123 | 124 | # replace item in line 125 | lines = [] 126 | with open(v['file']) as f: 127 | for line_i, line in enumerate(f): 128 | if line_i == v['line']: 129 | # 对没注释的行进行操作 130 | if not v['commented']: 131 | # 检测是否需要注释 132 | if commented: 133 | if v['count'] > 1: 134 | # delete this line, just ignore it 135 | pass 136 | else: 137 | # comment this line 138 | ######################################### 139 | # lines.append('#%s=%s\n' % (item, value)) 140 | lines.append('#%s\n' % (line,)) 141 | else: 142 | ######################################### 143 | lines.append('%s=%s\n' % (item, value)) 144 | else: 145 | if commented: 146 | # do not allow change comment value 147 | lines.append(line) 148 | pass 149 | else: 150 | # append a new line after comment line 151 | # lines.append(line) 152 | ######################################### 153 | lines.append('%s=%s\n' % (item, value)) 154 | else: 155 | lines.append(line) 156 | with open(v['file'], 'w') as f: 157 | f.write(''.join(lines)) 158 | else: 159 | # append to the end of file 160 | with open(v['file'], 'a') as f: 161 | f.write('\n%s%s = %s\n' % (commented and '#' or '', item, value)) 162 | 163 | return True 164 | #}}} 165 | if __name__ == '__main__': 166 | # import pprint 167 | # pp = pprint.PrettyPrinter(indent=4) 168 | # loadconfig() 169 | # pp.pprint(loadconfig()) 170 | print cfg_get('Hostname') #有#号的不显示 171 | # print cfg_get('Subsystem', detail=True) #detail显示细节 172 | # print cfg_set('Subsystem','') #直接注释 173 | # print cfg_set('Subsystem', '44444333') #设置值 174 | # # print cfg_set('Subsystem', 'sftp\t/usr/libexec/openssh/sftp-server',commented=False) 175 | # print cfg_get('Subsystem', detail=True) #detail显示细节 176 | 177 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [wei] 2 | corpid = wx3317042c8bcf7555 3 | corpsecret = z4RWpYBw3dzZYExmhmENw9vZ2UTDZQahIycjla55u9v2QdScQBjYTz0fTJ30RAqx 4 | agentid = 5 5 | toparty = 6 | web = http://192.168.1.199/zabbix/ 7 | author = 懒懒的天空 8 | [zabbix] 9 | user = Admin 10 | passwd = 123456 11 | -------------------------------------------------------------------------------- /get_pic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = 'bluetom' 4 | 5 | import sys 6 | import time 7 | import datetime 8 | from selenium import webdriver 9 | from conf.INIFILES import read_config 10 | from conf.BLog import Log 11 | import os 12 | 13 | 14 | def get_item_pic(url, user, passwd, itemid): 15 | try: 16 | driver = webdriver.PhantomJS("/usr/local/phantomjs-2.1.1/bin/phantomjs") 17 | driver.get(url) 18 | driver.set_window_size(640, 480) 19 | path = "/usr/lib/zabbix/alertscripts/pic" 20 | # path = "/tmp/pic" 21 | if not os.path.exists(path): 22 | os.makedirs(path) 23 | driver.find_element_by_id("name").send_keys(user) #输入用户名 24 | driver.find_element_by_id("password").send_keys(passwd) #输入用户名 25 | driver.find_element_by_id("enter").click() 26 | item_url = url + "history.php?action=showgraph&fullscreen=1&itemids[]=" + itemid 27 | driver.get(item_url) 28 | temp_name = itemid + "_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".png" 29 | time.sleep(0.5) 30 | driver.save_screenshot(temp_name) 31 | driver.close() 32 | driver.quit() 33 | return temp_name 34 | # shutil.move(temp_name, backpath) 35 | # im = Image.open(temp_name) 36 | # im = im.crop((0, 0, 640, 480)) 37 | # im.save(temp_name) 38 | except Exception, e: 39 | senderr = str(e) 40 | sendstatus = False 41 | 42 | def getpic(item_id): 43 | try: 44 | global sendstatus 45 | global senderr 46 | start = time.time() 47 | config_file_path = get_path() 48 | user = read_config(config_file_path, 'zabbix', "user") 49 | passwd = read_config(config_file_path, 'zabbix', "passwd") 50 | url = read_config(config_file_path, 'wei', "web") 51 | path = get_item_pic(url, user=user, passwd=passwd, itemid=item_id) 52 | sendstatus = True 53 | except Exception, e: 54 | senderr = str(e) 55 | sendstatus = False 56 | # logwrite(sendstatus, path) 57 | return path 58 | 59 | 60 | def logwrite(sendstatus, content): 61 | logpath = '/var/log/zabbix/weixin' 62 | # logpath = "log" 63 | if not sendstatus: 64 | content = senderr 65 | t = datetime.datetime.now() 66 | daytime = t.strftime('%Y-%m-%d') 67 | daylogfile = logpath+'/'+str(daytime)+'.log' 68 | logger = Log(daylogfile, level="info", is_console=False, mbs=5, count=5) 69 | os.system('chown zabbix.zabbix {0}'.format(daylogfile)) 70 | logger.info(content) 71 | 72 | 73 | def get_path(): 74 | path = os.path.dirname(os.path.abspath(sys.argv[0])) 75 | config_path = path + '/config.ini' 76 | return config_path 77 | 78 | 79 | if __name__ == "__main__": 80 | print getpic('24099') 81 | 82 | 83 | -------------------------------------------------------------------------------- /ghostdriver.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/ghostdriver.log -------------------------------------------------------------------------------- /problem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | <告警主机>{HOST.NAME} 4 | <告警地址>{HOST.IP} 5 | <告警时间>{EVENT.DATE} {EVENT.TIME} 6 | <告警等级>{TRIGGER.SEVERITY} 7 | <告警信息>{TRIGGER.NAME} 8 | <监控项目>{ITEM.NAME} 9 | <当前状态>{TRIGGER.STATUS} 10 | <持续时间>{EVENT.AGE} 11 | <事件ID>{EVENT.ID} 12 | <监控取值>{ITEM.LASTVALUE} 13 | <监控ID>{ITEM.ID} 14 | -------------------------------------------------------------------------------- /recover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | <告警主机>{HOST.NAME} 4 | <告警地址>{HOST.IP} 5 | <告警时间>{EVENT.DATE} {EVENT.TIME} 6 | <恢复时间>{EVENT.RECOVERY.DATE} {EVENT.RECOVERY.TIME} 7 | <告警等级>{TRIGGER.SEVERITY} 8 | <告警信息>{TRIGGER.NAME} 9 | <监控项目>{ITEM.NAME} 10 | <当前状态>{TRIGGER.STATUS} 11 | <持续时间>{EVENT.AGE} 12 | <事件ID>{EVENT.ID} 13 | <监控取值>{ITEM.LASTVALUE} 14 | <监控ID>{ITEM.ID} 15 | -------------------------------------------------------------------------------- /requests/Pillow-4.0.0-cp27-cp27m-manylinux1_x86_64.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/Pillow-4.0.0-cp27-cp27m-manylinux1_x86_64.whl -------------------------------------------------------------------------------- /requests/fontconfig-2.10.95-10.el7.x86_64.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/fontconfig-2.10.95-10.el7.x86_64.rpm -------------------------------------------------------------------------------- /requests/freetype-2.4.11-12.el7.x86_64.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/freetype-2.4.11-12.el7.x86_64.rpm -------------------------------------------------------------------------------- /requests/phantomjs-2.1.1-linux-x86_64.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/phantomjs-2.1.1-linux-x86_64.tar.bz2 -------------------------------------------------------------------------------- /requests/requests-2.12.4-py2.py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/requests-2.12.4-py2.py3-none-any.whl -------------------------------------------------------------------------------- /requests/requests-2.12.4.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/requests-2.12.4.tar.gz -------------------------------------------------------------------------------- /requests/selenium-3.0.2.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/requests/selenium-3.0.2.tar.gz -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | image==1.5.5 2 | lxml==3.5.0 3 | selenium==3.0.2 4 | -------------------------------------------------------------------------------- /test_xml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = 'bluetom' 4 | 5 | from lxml import etree 6 | xml_file = etree.parse('problem.xml') 7 | root_node = xml_file.getroot() 8 | a = root_node.find(u"告警等级").text 9 | print a 10 | 11 | root2 = etree.fromstring(open('problem.xml').read()) 12 | print root2.xpath(u"告警等级")[0].text 13 | print root2.xpath(u"监控项目")[0].text 14 | print root2.xpath(u"告警等级")[0].text -------------------------------------------------------------------------------- /weixin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluetom520/zabbix-weixin-picture/3a826ba16c77d22f43fa4e87d010e720bcdf8067/weixin.jpg -------------------------------------------------------------------------------- /weixin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = '懒懒的天空' 4 | 5 | import requests 6 | import sys 7 | import json 8 | import time 9 | import Image 10 | from conf.INIFILES import read_config, write_config 11 | from selenium import webdriver 12 | import os 13 | import datetime 14 | from conf.BLog import Log 15 | from get_pic import getpic 16 | import re 17 | from lxml import etree 18 | reload(sys) 19 | sys.setdefaultencoding('utf-8') 20 | 21 | 22 | class WeiXin(object): 23 | def __init__(self, corpid, corpsecret): # 初始化的时候需要获取corpid和corpsecret,需要从管理后台获取 24 | self.__params = { 25 | 'corpid': corpid, 26 | 'corpsecret': corpsecret 27 | } 28 | 29 | self.url_get_token = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken' 30 | self.url_send = 'https://qyapi.weixin.qq.com/cgi-bin/message/send' 31 | self.url_uploadimg = 'https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg' 32 | self.img_url = 'https://qyapi.weixin.qq.com/cgi-bin/media/upload' 33 | 34 | self.__token = self.__get_token() 35 | self.__token_params = { 36 | 'access_token': self.__token 37 | } 38 | 39 | def __raise_error(self, res): 40 | raise Exception('error code: %s,error message: %s' % (res.json()['errcode'], res.json()['errmsg'])) 41 | global senderr 42 | global sendstatus 43 | sendstatus = False 44 | senderr = 'error code: %s,error message: %s' % (res.json()['errcode'], res.json()['errmsg']) 45 | 46 | def __get_token(self): 47 | # print self.url_get_token 48 | headers = {'content-type': 'application/json'} 49 | res = requests.get(self.url_get_token, headers=headers, params=self.__params) 50 | 51 | try: 52 | return res.json()['access_token'] 53 | except: 54 | self.__raise_error(res.content) 55 | 56 | 57 | def send_message(self, agentid, messages, userid='', toparty=''): 58 | payload = { 59 | 'touser': userid, 60 | 'toparty': toparty, 61 | 'agentid': agentid, 62 | "msgtype": "news", 63 | "news": messages 64 | } 65 | headers = {'content-type': 'application/json'} 66 | data = json.dumps(payload, ensure_ascii=False).encode('utf-8') 67 | params = self.__token_params 68 | res = requests.post(self.url_send, headers=headers, params=params, data=data) 69 | try: 70 | return res.json() 71 | except: 72 | self.__raise_error(res) 73 | 74 | def send_message_mediaid(self, agentid, messages, userid='', toparty=''): 75 | payload = { 76 | 'touser': userid, 77 | 'toparty': toparty, 78 | 'agentid': agentid, 79 | "msgtype": "mpnews", 80 | "mpnews": messages 81 | } 82 | headers = {'content-type': 'application/json'} 83 | data = json.dumps(payload, ensure_ascii=False).encode('utf-8') 84 | params = self.__token_params 85 | res = requests.post(self.url_send, headers=headers, params=params, data=data) 86 | try: 87 | return res.json() 88 | except: 89 | self.__raise_error(res) 90 | 91 | def get_media_ID(self, path): 92 | try: 93 | params = self.__token_params 94 | params['type'] = "image" 95 | data = {'media': open(path, 'rb')} 96 | r = requests.post(url=self.img_url, params=params, files=data) 97 | dict = r.json() 98 | return dict['media_id'] 99 | except: 100 | self.__raise_error(r) 101 | 102 | def get_imaging(self, path): 103 | try: 104 | params = self.__token_params 105 | data = {'media': open(path, 'rb')} 106 | r = requests.post(url=self.url_uploadimg, params=params, files=data) 107 | dict = r.json() 108 | return dict['url'] 109 | except: 110 | self.__raise_error(r) 111 | 112 | def get_image(self, path): 113 | try: 114 | params = self.__token_params 115 | headers = {'content-type': 'application/json'} 116 | data = {'type': "image", 'media': open(path, 'rb')} 117 | r = requests.post(url=self.img_url, params=params, headers=headers, files=data) 118 | dict = r.json() 119 | return dict['url'] 120 | except: 121 | self.__raise_error(r) 122 | 123 | def main(send_to, subject, content): 124 | try: 125 | global sendstatus 126 | global senderr 127 | data = '' 128 | messages = {} 129 | body = {} 130 | config_file_path = get_path() 131 | CorpID = read_config(config_file_path, 'wei', "CorpID") 132 | CorpSecret = read_config(config_file_path, 'wei', "CorpSecret") 133 | agentid = read_config(config_file_path, 'wei', "agentid") 134 | web = read_config(config_file_path, 'wei', "web") 135 | author = read_config(config_file_path, 'wei', "author") 136 | # content = json.loads(content) 137 | messages["message_url"] = web 138 | root = etree.fromstring(content) 139 | itemid = root.xpath(u"监控ID")[0].text 140 | itemvalue = root.xpath(u"监控取值")[0].text 141 | s = re.match(r'^[0-9\.]+(\s\w{0,3})?$', itemvalue) 142 | # s = re.match(r'^[0-9\.]+$', itemvalue.split(' ')[0]) 143 | if s: 144 | body["content_source_url"] = web + "history.php?action=showgraph&itemids[]=" + itemid 145 | else: 146 | body["content_source_url"] = web + "history.php?action=showvalues&itemids[]=" + itemid 147 | warn_message = '' 148 | if root.xpath(u"当前状态")[0].text == 'PROBLEM': 149 | body["title"] = "服务器故障" 150 | warn_message += subject + '\n' 151 | warn_message += '详情:\n' 152 | warn_message += '告警等级:' + root.xpath(u"告警等级")[0].text + '\n' 153 | warn_message += '告警时间:' + root.xpath(u"告警时间")[0].text + '\n' 154 | warn_message += '告警地址:' + root.xpath(u"告警地址")[0].text + '\n' 155 | warn_message += '持续时间:' + root.xpath(u"持续时间")[0].text + '\n' 156 | warn_message += '监控项目:' + root.xpath(u"监控项目")[0].text + '\n' 157 | warn_message += root.xpath(u"告警主机")[0].text + '故障(' + root.xpath(u"事件ID")[0].text+ ')' 158 | else: 159 | body["title"] = "服务器恢复" 160 | warn_message += subject + '\n' 161 | warn_message += '详情:\n' 162 | warn_message += '告警等级:' + root.xpath(u"告警等级")[0].text + '\n' 163 | warn_message += '恢复时间:' + root.xpath(u"恢复时间")[0].text + '\n' 164 | warn_message += '告警地址:' + root.xpath(u"告警地址")[0].text + '\n' 165 | warn_message += '持续时间:' + root.xpath(u"持续时间")[0].text + '\n' 166 | warn_message += '监控项目:' + root.xpath(u"监控项目")[0].text + '\n' 167 | warn_message += root.xpath(u"告警主机")[0].text + '恢复(' + root.xpath(u"事件ID")[0].text+ ')' 168 | body['digest'] = warn_message 169 | warn_message = '' 170 | if root.xpath(u"当前状态")[0].text == 'PROBLEM': 171 | body["title"] = "服务器故障" 172 | warn_message += '

'+subject + '

' + '\n' 173 | warn_message += '

'+'详情:' + '

' + '\n' 174 | warn_message += '

'+'告警等级:' + root.xpath(u"告警等级")[0].text + '

' + '\n' 175 | warn_message += '

'+'告警时间:' + root.xpath(u"告警时间")[0].text + '

'+ '\n' 176 | warn_message += '

'+'告警地址:' + root.xpath(u"告警地址")[0].text + '

'+ '\n' 177 | warn_message += '

'+'持续时间:' + root.xpath(u"持续时间")[0].text + '

'+ '\n' 178 | warn_message += '

'+'监控项目:' + root.xpath(u"监控项目")[0].text + '

'+ '\n' 179 | warn_message += '

'+root.xpath(u"告警主机")[0].text + '故障(' + root.xpath(u"事件ID")[0].text+ ')'+'

' 180 | else: 181 | body["title"] = "服务器恢复" 182 | warn_message += '

'+subject + '

' + '\n' 183 | warn_message += '

'+'详情:' + '

' + '\n' 184 | warn_message += '

'+'告警等级:' + root.xpath(u"告警等级")[0].text + '

' + '\n' 185 | warn_message += '

'+'恢复时间:' + root.xpath(u"恢复时间")[0].text + '

'+ '\n' 186 | warn_message += '

'+'告警地址:' + root.xpath(u"告警地址")[0].text + '

'+ '\n' 187 | warn_message += '

'+'持续时间:' + root.xpath(u"持续时间")[0].text + '

'+ '\n' 188 | warn_message += '

'+'监控项目:' + root.xpath(u"监控项目")[0].text + '

'+ '\n' 189 | warn_message += '

'+root.xpath(u"告警主机")[0].text + '恢复(' + root.xpath(u"事件ID")[0].text+ ')'+'

' 190 | body['content'] = warn_message 191 | body['author'] = author 192 | wx = WeiXin(CorpID, CorpSecret) 193 | pic_path = getpic(itemid, s) 194 | picurl = wx.get_media_ID(pic_path) 195 | body['thumb_media_id'] = picurl 196 | data = [] 197 | data.append(body) 198 | messages['articles'] = data 199 | data = wx.send_message_mediaid(toparty=send_to, agentid=agentid, messages=messages) 200 | sendstatus = True 201 | except Exception, e: 202 | senderr = str(e) 203 | sendstatus = False 204 | logwrite(sendstatus, data) 205 | 206 | 207 | def get_path(): 208 | path = os.path.dirname(os.path.abspath(sys.argv[0])) 209 | config_path = path + '/config.ini' 210 | return config_path 211 | 212 | 213 | def logwrite(sendstatus, content): 214 | logpath = '/var/log/zabbix/weixin' 215 | if not sendstatus: 216 | content = senderr 217 | t = datetime.datetime.now() 218 | daytime = t.strftime('%Y-%m-%d') 219 | daylogfile = logpath+'/'+str(daytime)+'.log' 220 | logger = Log(daylogfile, level="info", is_console=False, mbs=5, count=5) 221 | os.system('chown zabbix.zabbix {0}'.format(daylogfile)) 222 | logger.info(content) 223 | 224 | 225 | def get_item_pic(url, user, passwd, itemid, flag): 226 | try: 227 | driver = webdriver.PhantomJS("/usr/local/phantomjs-2.1.1/bin/phantomjs",service_log_path=os.path.devnull) 228 | # driver = webdriver.PhantomJS(executable_path='/usr/local/phantomjs-2.1.1/bin/phantomjs', service_log_path='/var/log/ghostdriver.log', service_args=["--webdriver-loglevel=NONE"]) 229 | driver.get(url) 230 | driver.set_window_size(640, 480) 231 | picpath = "/usr/lib/zabbix/alertscripts/pic" 232 | driver.find_element_by_id("name").send_keys(user) #输入用户名 233 | driver.find_element_by_id("password").send_keys(passwd) #输入用户名 234 | driver.find_element_by_id("enter").click() 235 | if flag: 236 | item_url = url + "history.php?action=showgraph&fullscreen=1&itemids[]=" + itemid 237 | else: 238 | item_url = url + "history.php?action=showvalues&fullscreen=1&itemids[]=" + itemid 239 | driver.get(item_url) 240 | temp_name = picpath+"/"+itemid + "_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".png" 241 | # logwrite(True, temp_name) 242 | time.sleep(0.5) 243 | driver.save_screenshot(temp_name) 244 | driver.close() 245 | driver.quit() 246 | # shutil.move(temp_name, backpath) 247 | if not flag: 248 | im = Image.open(temp_name) 249 | im = im.crop((0, 0, 640, 480)) 250 | im.save(temp_name) 251 | return temp_name 252 | except Exception, e: 253 | global senderr 254 | senderr = str(e) 255 | global sendstatus 256 | sendstatus = False 257 | logwrite(sendstatus, e) 258 | 259 | 260 | def getpic(item_id, s): 261 | try: 262 | config_file_path = get_path() 263 | user = read_config(config_file_path, 'zabbix', "user") 264 | passwd = read_config(config_file_path, 'zabbix', "passwd") 265 | url = read_config(config_file_path, 'wei', "web") 266 | ppath = get_item_pic(url, user=user, passwd=passwd, itemid=item_id, flag=s) 267 | global sendstatus 268 | sendstatus = True 269 | return ppath 270 | except Exception, e: 271 | global senderr 272 | senderr = str(e) 273 | sendstatus = False 274 | logwrite(sendstatus, e) 275 | 276 | 277 | if __name__ == "__main__": 278 | if len(sys.argv) > 1: 279 | send_to = sys.argv[1] 280 | subject = sys.argv[2] 281 | content = sys.argv[3] 282 | logwrite(True, content) 283 | main(send_to, subject, content) 284 | 285 | 286 | -------------------------------------------------------------------------------- /weixin_bak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # __author__ = '懒懒的天空' 4 | 5 | import requests 6 | import sys 7 | import json 8 | import time 9 | import Image 10 | from conf.INIFILES import read_config, write_config 11 | from selenium import webdriver 12 | import os 13 | import datetime 14 | from conf.BLog import Log 15 | from get_pic import getpic 16 | import re 17 | 18 | reload(sys) 19 | sys.setdefaultencoding('utf-8') 20 | 21 | 22 | class WeiXin(object): 23 | def __init__(self, corpid, corpsecret): # 初始化的时候需要获取corpid和corpsecret,需要从管理后台获取 24 | self.__params = { 25 | 'corpid': corpid, 26 | 'corpsecret': corpsecret 27 | } 28 | 29 | self.url_get_token = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken' 30 | self.url_send = 'https://qyapi.weixin.qq.com/cgi-bin/message/send' 31 | self.url_uploadimg = 'https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg' 32 | self.img_url = 'https://qyapi.weixin.qq.com/cgi-bin/media/upload' 33 | 34 | self.__token = self.__get_token() 35 | self.__token_params = { 36 | 'access_token': self.__token 37 | } 38 | 39 | def __raise_error(self, res): 40 | raise Exception('error code: %s,error message: %s' % (res.json()['errcode'], res.json()['errmsg'])) 41 | global senderr 42 | global sendstatus 43 | sendstatus = False 44 | senderr = 'error code: %s,error message: %s' % (res.json()['errcode'], res.json()['errmsg']) 45 | 46 | def __get_token(self): 47 | # print self.url_get_token 48 | headers = {'content-type': 'application/json'} 49 | res = requests.get(self.url_get_token, headers=headers, params=self.__params) 50 | 51 | try: 52 | return res.json()['access_token'] 53 | except: 54 | self.__raise_error(res.content) 55 | 56 | 57 | def send_message(self, agentid, messages, userid='', toparty=''): 58 | payload = { 59 | 'touser': userid, 60 | 'toparty': toparty, 61 | 'agentid': agentid, 62 | "msgtype": "news", 63 | "news": messages 64 | } 65 | headers = {'content-type': 'application/json'} 66 | data = json.dumps(payload, ensure_ascii=False).encode('utf-8') 67 | params = self.__token_params 68 | res = requests.post(self.url_send, headers=headers, params=params, data=data) 69 | try: 70 | return res.json() 71 | except: 72 | self.__raise_error(res) 73 | 74 | def get_media_ID(self, path): 75 | params = self.__token_params 76 | params['type'] = 'image\r\n' 77 | data = {'media': open(path, 'rb')} 78 | r = requests.post(url=self.img_url, params=params, files=data) 79 | dict = r.json() 80 | return dict['media_id'] 81 | 82 | def get_imaging(self, path): 83 | params = self.__token_params 84 | data = {'media': open(path, 'rb')} 85 | r = requests.post(url=self.url_uploadimg, params=params, files=data) 86 | dict = r.json() 87 | return dict['url'] 88 | 89 | 90 | def main(send_to, subject, content, value): 91 | try: 92 | global sendstatus 93 | global senderr 94 | data = '' 95 | messages = {} 96 | body = {} 97 | config_file_path = get_path() 98 | CorpID = read_config(config_file_path, 'wei', "CorpID") 99 | CorpSecret = read_config(config_file_path, 'wei', "CorpSecret") 100 | agentid = read_config(config_file_path, 'wei', "agentid") 101 | web = read_config(config_file_path, 'wei', "web") 102 | content = json.loads(content) 103 | messages["message_url"] = web 104 | itemid = content[u'监控ID'] 105 | itemvalue = value 106 | s = re.match(r'^[0-9\.]+$', itemvalue) 107 | if s: 108 | body["url"] = web + "history.php?action=showgraph&itemids[]=" + itemid 109 | else: 110 | body["url"] = web + "history.php?action=showvalues&itemids[]=" + itemid 111 | warn_message = '' 112 | if content[u'当前状态'] == 'PROBLEM': 113 | body["title"] = "服务器故障" 114 | warn_message += subject + '\n' 115 | warn_message += '详情:\n' 116 | warn_message += '告警等级:'+ content[u'告警等级'] + '\n' 117 | warn_message += '告警时间:'+ content[u'告警时间'] + '\n' 118 | warn_message += '告警地址:'+ content[u'告警地址'] + '\n' 119 | warn_message += '持续时间:'+ content[u'持续时间'] + '\n' 120 | warn_message += '监控项目:'+ content[u'监控项目'] + '\n' 121 | warn_message += content[u'告警主机'] + '故障(' + content[u'事件ID']+ ')' 122 | else: 123 | body["title"] = "服务器恢复" 124 | warn_message += subject + '\n' 125 | warn_message += '详情:\n' 126 | warn_message += '告警等级:'+ content[u'告警等级'] + '\n' 127 | warn_message += '恢复时间:'+ content[u'恢复时间'] + '\n' 128 | warn_message += '告警地址:'+ content[u'告警地址'] + '\n' 129 | warn_message += '持续时间:'+ content[u'持续时间'] + '\n' 130 | warn_message += '监控项目:'+ content[u'监控项目'] + '\n' 131 | warn_message += content[u'告警主机'] + '恢复(' + content[u'事件ID']+ ')' 132 | body["title"] = "服务器故障" 133 | body['description'] = warn_message 134 | wx = WeiXin(CorpID, CorpSecret) 135 | pic_path = getpic(itemid,s) 136 | picurl = wx.get_imaging(pic_path) 137 | body['picurl'] = picurl 138 | data = [] 139 | data.append(body) 140 | messages['articles'] = data 141 | data = wx.send_message(toparty=send_to, agentid=agentid, messages=messages) 142 | sendstatus = True 143 | except Exception, e: 144 | senderr = str(e) 145 | sendstatus = False 146 | logwrite(sendstatus, data) 147 | 148 | 149 | def get_path(): 150 | path = os.path.dirname(os.path.abspath(sys.argv[0])) 151 | config_path = path + '/config.ini' 152 | return config_path 153 | 154 | 155 | def logwrite(sendstatus, content): 156 | logpath = '/var/log/zabbix/weixin' 157 | if not sendstatus: 158 | content = senderr 159 | t = datetime.datetime.now() 160 | daytime = t.strftime('%Y-%m-%d') 161 | daylogfile = logpath+'/'+str(daytime)+'.log' 162 | logger = Log(daylogfile, level="info", is_console=False, mbs=5, count=5) 163 | os.system('chown zabbix.zabbix {0}'.format(daylogfile)) 164 | logger.info(content) 165 | 166 | 167 | def get_item_pic(url, user, passwd, itemid, flag): 168 | try: 169 | driver = webdriver.PhantomJS("/usr/local/phantomjs-2.1.1/bin/phantomjs",service_log_path=os.path.devnull) 170 | # driver = webdriver.PhantomJS(executable_path='/usr/local/phantomjs-2.1.1/bin/phantomjs', service_log_path='/var/log/ghostdriver.log', service_args=["--webdriver-loglevel=NONE"]) 171 | driver.get(url) 172 | driver.set_window_size(640, 480) 173 | picpath = "/usr/lib/zabbix/alertscripts/pic" 174 | driver.find_element_by_id("name").send_keys(user) #输入用户名 175 | driver.find_element_by_id("password").send_keys(passwd) #输入用户名 176 | driver.find_element_by_id("enter").click() 177 | if flag: 178 | item_url = url + "history.php?action=showgraph&fullscreen=1&itemids[]=" + itemid 179 | else: 180 | item_url = url + "history.php?action=showvalues&fullscreen=1&itemids[]=" + itemid 181 | driver.get(item_url) 182 | temp_name = picpath+"/"+itemid + "_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".png" 183 | time.sleep(0.5) 184 | driver.save_screenshot(temp_name) 185 | driver.close() 186 | driver.quit() 187 | # shutil.move(temp_name, backpath) 188 | if flag: 189 | im = Image.open(temp_name) 190 | im = im.crop((0, 0, 640, 480)) 191 | im.save(temp_name) 192 | return temp_name 193 | except Exception, e: 194 | global senderr 195 | senderr = str(e) 196 | global sendstatus 197 | sendstatus = False 198 | logwrite(sendstatus, e) 199 | 200 | 201 | def getpic(item_id, s): 202 | try: 203 | config_file_path = get_path() 204 | user = read_config(config_file_path, 'zabbix', "user") 205 | passwd = read_config(config_file_path, 'zabbix', "passwd") 206 | url = read_config(config_file_path, 'wei', "web") 207 | ppath = get_item_pic(url, user=user, passwd=passwd, itemid=item_id, flag=s) 208 | global sendstatus 209 | sendstatus = True 210 | return ppath 211 | except Exception, e: 212 | global senderr 213 | senderr = str(e) 214 | sendstatus = False 215 | logwrite(sendstatus, e) 216 | 217 | 218 | if __name__ == "__main__": 219 | if len(sys.argv) > 1: 220 | send_to = sys.argv[1] 221 | subject = sys.argv[2] 222 | content = sys.argv[3] 223 | itemvalue = sys.argv[4] 224 | logwrite(True, content) 225 | main(send_to, subject, content, itemvalue) 226 | 227 | 228 | --------------------------------------------------------------------------------