├── .fuse_hidden000012f500000001
├── .idea
├── encodings.xml
├── misc.xml
├── modules.xml
├── weixin.iml
└── workspace.xml
├── IMG_20170109_205046.png
├── IMG_20170109_205115.png
├── README.md
├── conf
├── BLog.py
├── BLog.pyc
├── INIFILES.py
├── INIFILES.pyc
├── __init__.py
├── __init__.pyc
└── file_util.py
├── config.ini
├── requests
├── requests-2.12.4-py2.py3-none-any.whl
└── requests-2.12.4.tar.gz
├── requirements.txt
└── weixin.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 |
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 | 1483953404466
39 |
40 | 1483953404466
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/IMG_20170109_205046.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/IMG_20170109_205046.png
--------------------------------------------------------------------------------
/IMG_20170109_205115.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/IMG_20170109_205115.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
17 | ```
18 | git clone https://github.com/bluetom520/zabbix-weixin.git
19 | pip install requests/requests-2.12.4-py2.py3-none-any.whl
20 | cp dingding/* /usr/lib/zabbix/alertscripts/
21 | chown -R zabbix:zabbix /usr/lib/zabbix/alertscripts/dingding.py
22 | chmod +x /usr/lib/zabbix/alertscripts/dingding.py
23 | chmod a+w /usr/lib/zabbix/alertscripts/config.ini
24 |
25 | ```
26 | 修改config.ini,把上节获得的三个参数填入,web是点击报警信息后跳转的页面,设置的监控数据的最新出图,但手机浏览器不支持。后面看怎么把图抓下来放到微信报警里面,抓图早已经实现了,看大家有没有兴趣了,有兴趣我加再加:)
27 | ```
28 | [wei]
29 | corpid = wx3317042c8bcf7551
30 | corpsecret = m0VqePgfDsTbVoFlGSx5-JOCbE5p43rf5G-GC2CqN4Wq2Ce0OJQkgo0JnXMqKypv
31 | agentid = 2
32 | toparty =
33 | web = http://192.168.1.199/zabbix/
34 | ```
35 | ### 3 ZABBIX配置
36 | #### 3.1 报警媒介类型
37 | 到管理-》报警媒介类型配置我们的微信
38 | 
39 | #### 3.2 配置用户
40 | 到管理-》用户-》报警媒介-》添加,注意填写收件人为我们之前设置的运维部id 2
41 | 
42 | #### 3.3 动作设置
43 | 到配置-》动作-》创建动作(触发器)
44 | - 动作
45 | 
46 | ```
47 | 服务器:{HOST.NAME}: {TRIGGER.NAME}已恢复!
48 |
49 | {
50 | "告警主机":"{HOST.NAME}",
51 | "告警地址":"{HOST.IP}",
52 | "告警时间":"{EVENT.DATE} {EVENT.TIME}",
53 | "恢复时间":"{EVENT.RECOVERY.DATE} {EVENT.RECOVERY.TIME}",
54 | "告警等级":"{TRIGGER.SEVERITY}",
55 | "告警信息":"{TRIGGER.NAME}",
56 | "监控项目":"{ITEM.NAME}",
57 | "当前状态":"{TRIGGER.STATUS}",
58 | "持续时间":"{EVENT.AGE}",
59 | "事件ID":"{EVENT.ID}",
60 | "监控ID":"{ITEM.ID}",
61 | "监控取值":"{ITEM.LASTVALUE}"
62 | }
63 |
64 | 服务器:{HOST.NAME}发生: {TRIGGER.NAME}故障!
65 |
66 | {
67 | "告警主机":"{HOST.NAME}",
68 | "告警地址":"{HOST.IP}",
69 | "告警时间":"{EVENT.DATE} {EVENT.TIME}",
70 | "告警等级":"{TRIGGER.SEVERITY}",
71 | "告警信息":"{TRIGGER.NAME}",
72 | "监控项目":"{ITEM.NAME}",
73 | "当前状态":"{TRIGGER.STATUS}",
74 | "持续时间":"{EVENT.AGE}",
75 | "事件ID":"{EVENT.ID}",
76 | "监控ID":"{ITEM.ID}",
77 | "监控取值":"{ITEM.LASTVALUE}"
78 | }
79 | ```
80 | - 条件
81 | 
82 | - 操作
83 | 
84 |
85 | ### 4 效果展现
86 | 故障图
87 | 
88 | 恢复图
89 | 
90 |
91 | ### 5 docker环境修改
92 | ```
93 | tar zxvf requests-2.12.4.tar.gz
94 | docker cp requests-2.12.4 zabbix:/usr/local/share/zabbix/alertscripts
95 | docker cp dingding zabbix:/usr/local/share/zabbix/alertscripts
96 | docker exec -it zabbix /bin/bash
97 | cd /usr/local/share/zabbix/alertscripts/requests-2.12.4
98 | python setup.py install
99 | rm -rf requests-2.12.4
100 | cd ..
101 | mv zabbix-weixin/* .
102 | vi config.ini
103 | exit
104 | docker restart zabbix
105 |
106 | ```
107 |
--------------------------------------------------------------------------------
/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/BLog.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/conf/BLog.pyc
--------------------------------------------------------------------------------
/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/INIFILES.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/conf/INIFILES.pyc
--------------------------------------------------------------------------------
/conf/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding:utf-8 -*-
3 | # __author__ = 'bluetom'
--------------------------------------------------------------------------------
/conf/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/conf/__init__.pyc
--------------------------------------------------------------------------------
/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 = m0VqePgfDsTbVoFlGSx5-JOCbE5p43rf5G-GC2CqN4Wq2Ce0OJQkgo0JnXMqKyQv
4 | agentid = 2
5 | toparty =
6 | web = http://192.168.1.199/zabbix/
7 |
8 |
--------------------------------------------------------------------------------
/requests/requests-2.12.4-py2.py3-none-any.whl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/requests/requests-2.12.4-py2.py3-none-any.whl
--------------------------------------------------------------------------------
/requests/requests-2.12.4.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluetom520/zabbix-weixin/c40cfb7036b30813bd45b28c1e379b0ea8ca18a6/requests/requests-2.12.4.tar.gz
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/weixin.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding:utf-8 -*-
3 | # __author__ = '懒懒的天空'
4 |
5 | import requests
6 | import sys
7 | import json
8 | from conf.INIFILES import read_config, write_config
9 | import os
10 | import datetime
11 | from conf.BLog import Log
12 | reload(sys)
13 | sys.setdefaultencoding('utf-8')
14 |
15 |
16 | class WeiXin(object):
17 | def __init__(self, corpid, corpsecret): # 初始化的时候需要获取corpid和corpsecret,需要从管理后台获取
18 | self.__params = {
19 | 'corpid': corpid,
20 | 'corpsecret': corpsecret
21 | }
22 |
23 | self.url_get_token = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
24 | self.url_send = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?'
25 |
26 | self.__token = self.__get_token()
27 | self.__token_params = {
28 | 'access_token': self.__token
29 | }
30 |
31 | def __raise_error(self, res):
32 | raise Exception('error code: %s,error message: %s' % (res.json()['errcode'], res.json()['errmsg']))
33 | global senderr
34 | sendstatus = False
35 | senderr = 'error code: %s,error message: %s' % (res.json()['errcode'], res.json()['errmsg'])
36 |
37 | def __get_token(self):
38 | # print self.url_get_token
39 | headers = {'content-type': 'application/json'}
40 | res = requests.get(self.url_get_token, headers=headers, params=self.__params)
41 |
42 | try:
43 | return res.json()['access_token']
44 | except:
45 | self.__raise_error(res.content)
46 |
47 |
48 | def send_message(self, agentid, messages, userid='', toparty=''):
49 | payload = {
50 | 'touser': userid,
51 | 'toparty': toparty,
52 | 'agentid': agentid,
53 | "msgtype": "news",
54 | "news": messages
55 | }
56 | headers = {'content-type': 'application/json'}
57 | data = json.dumps(payload, ensure_ascii=False).encode('utf-8')
58 | params = self.__token_params
59 | res = requests.post(self.url_send, headers=headers, params=params, data=data)
60 | try:
61 | return res.json()
62 | except:
63 | self.__raise_error(res)
64 |
65 |
66 | def main(send_to, subject, content):
67 | try:
68 | global sendstatus
69 | global senderr
70 | data = ''
71 | messages = {}
72 | body = {}
73 | config_file_path = get_path()
74 | CorpID = read_config(config_file_path, 'wei', "CorpID")
75 | CorpSecret = read_config(config_file_path, 'wei', "CorpSecret")
76 | agentid = read_config(config_file_path, 'wei', "agentid")
77 | web = read_config(config_file_path, 'wei', "web")
78 | content = json.loads(content)
79 | messages["message_url"] = web
80 | body["url"] = web + "history.php?action=showgraph&itemids[]=" + content[u'监控ID']
81 | warn_message = ''
82 | if content[u'当前状态'] == 'PROBLEM':
83 | body["title"] = "服务器故障"
84 | warn_message += subject + '\n'
85 | warn_message += '详情:\n'
86 | warn_message += '告警等级:'+ content[u'告警等级'] + '\n'
87 | warn_message += '告警时间:'+ content[u'告警时间'] + '\n'
88 | warn_message += '告警地址:'+ content[u'告警地址'] + '\n'
89 | warn_message += '持续时间:'+ content[u'持续时间'] + '\n'
90 | warn_message += '监控项目:'+ content[u'监控项目'] + '\n'
91 | warn_message += content[u'告警主机'] + '故障(' + content[u'事件ID']+ ')'
92 | else:
93 | body["title"] = "服务器恢复"
94 | warn_message += subject + '\n'
95 | warn_message += '详情:\n'
96 | warn_message += '告警等级:'+ content[u'告警等级'] + '\n'
97 | warn_message += '恢复时间:'+ content[u'恢复时间'] + '\n'
98 | warn_message += '告警地址:'+ content[u'告警地址'] + '\n'
99 | warn_message += '持续时间:'+ content[u'持续时间'] + '\n'
100 | warn_message += '监控项目:'+ content[u'监控项目'] + '\n'
101 | warn_message += content[u'告警主机'] + '恢复(' + content[u'事件ID']+ ')'
102 | body['description'] = warn_message
103 | data = []
104 | data.append(body)
105 | messages['articles'] = data
106 | wx = WeiXin(CorpID, CorpSecret)
107 | data = wx.send_message(toparty=send_to, agentid=agentid, messages=messages)
108 | sendstatus = True
109 | except Exception, e:
110 | senderr = str(e)
111 | sendstatus = False
112 | logwrite(sendstatus, data)
113 |
114 |
115 | def get_path():
116 | path = os.path.dirname(os.path.abspath(sys.argv[0]))
117 | config_path = path + '/config.ini'
118 | return config_path
119 |
120 |
121 | def logwrite(sendstatus, content):
122 | logpath = '/var/log/zabbix/weixin'
123 | if not sendstatus:
124 | content = senderr
125 | t = datetime.datetime.now()
126 | daytime = t.strftime('%Y-%m-%d')
127 | daylogfile = logpath+'/'+str(daytime)+'.log'
128 | logger = Log(daylogfile, level="info", is_console=False, mbs=5, count=5)
129 | os.system('chown zabbix.zabbix {0}'.format(daylogfile))
130 | logger.info(content)
131 |
132 | if __name__ == "__main__":
133 | if len(sys.argv) > 1:
134 | send_to = sys.argv[1]
135 | subject = sys.argv[2]
136 | content = sys.argv[3]
137 | logwrite(True, content)
138 | main(send_to, subject, content)
139 |
140 |
--------------------------------------------------------------------------------