/Nagstamon/Nagstamon/thirdparty/zabbix_api.py

https://github.com/clark42/Nagstamon · Python · 352 lines · 240 code · 53 blank · 59 comment · 29 complexity · 335ca9d78aa8bb178b874f302077d8a7 MD5 · raw file

  1. # This is a port of the ruby zabbix api found here:
  2. # http://trac.red-tux.net/browser/ruby/api/zbx_api.rb
  3. #
  4. #LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
  5. #Zabbix API Python Library.
  6. #Original Ruby Library is Copyright (C) 2009 Andrew Nelson nelsonab(at)red-tux(dot)net
  7. #Python Library is Copyright (C) 2009 Brett Lentz brett.lentz(at)gmail(dot)com
  8. #
  9. #This library is free software; you can redistribute it and/or
  10. #modify it under the terms of the GNU Lesser General Public
  11. #License as published by the Free Software Foundation; either
  12. #version 2.1 of the License, or (at your option) any later version.
  13. #
  14. #This library is distributed in the hope that it will be useful,
  15. #but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. #Lesser General Public License for more details.
  18. #
  19. #You should have received a copy of the GNU Lesser General Public
  20. #License along with this library; if not, write to the Free Software
  21. #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. # NOTES:
  23. # The API requires zabbix 1.8 or later.
  24. # Currently, not all of the API is implemented, and some functionality is
  25. # broken. This is a work in progress.
  26. import base64
  27. import hashlib
  28. import logging
  29. import string
  30. import sys
  31. try:
  32. import urllib2
  33. except ImportError:
  34. import urllib.request as urllib2 # python3
  35. import re
  36. from collections import deque
  37. default_log_handler = logging.StreamHandler(sys.stdout)
  38. __logger = logging.getLogger("zabbix_api")
  39. __logger.addHandler(default_log_handler)
  40. __logger.log(10, "Starting logging")
  41. try:
  42. # Separate module or Python <2.6
  43. import simplejson as json
  44. __logger.log(15, "Using simplejson library")
  45. except ImportError:
  46. # Python >=2.6
  47. import json
  48. __logger.log(15, "Using native json library")
  49. def checkauth(fn):
  50. """ Decorator to check authentication of the decorated method """
  51. def ret(self, *args):
  52. self.__checkauth__()
  53. return fn(self, args)
  54. return ret
  55. def dojson(name):
  56. def decorator(fn):
  57. def wrapper(self, opts):
  58. self.logger.log(logging.DEBUG, \
  59. "Going to do_request for %s with opts %s" \
  60. % (repr(fn), repr(opts)))
  61. return self.do_request(self.json_obj(name, opts))['result']
  62. return wrapper
  63. return decorator
  64. def dojson2(fn):
  65. def wrapper(self, method, opts):
  66. self.logger.log(logging.DEBUG, \
  67. "Going to do_request for %s with opts %s" \
  68. % (repr(fn), repr(opts)))
  69. return self.do_request(self.json_obj(method, opts))['result']
  70. return wrapper
  71. class ZabbixAPIException(Exception):
  72. """ generic zabbix api exception
  73. code list:
  74. -32602 - Invalid params (eg already exists)
  75. -32500 - no permissions
  76. """
  77. pass
  78. class Already_Exists(ZabbixAPIException):
  79. pass
  80. class InvalidProtoError(ZabbixAPIException):
  81. """ Recived an invalid proto """
  82. pass
  83. class ZabbixAPI(object):
  84. __username__ = ''
  85. __password__ = ''
  86. auth = ''
  87. url = '/api_jsonrpc.php'
  88. params = None
  89. method = None
  90. # HTTP or HTTPS
  91. proto = 'http'
  92. # HTTP authentication
  93. httpuser = None
  94. httppasswd = None
  95. timeout = 10
  96. # sub-class instances.
  97. user = None
  98. usergroup = None
  99. host = None
  100. item = None
  101. hostgroup = None
  102. application = None
  103. trigger = None
  104. sysmap = None
  105. template = None
  106. drule = None
  107. # Constructor Params:
  108. # server: Server to connect to
  109. # path: Path leading to the zabbix install
  110. # proto: Protocol to use. http or https
  111. # We're going to use proto://server/path to find the JSON-RPC api.
  112. #
  113. # user: HTTP auth username
  114. # passwd: HTTP auth password
  115. # log_level: logging level
  116. # r_query_len: max len query history
  117. # **kwargs: Data to pass to each api module
  118. def __init__(self, server='http://localhost/zabbix', user=None, passwd=None,
  119. log_level=logging.WARNING, timeout=10, r_query_len=10, **kwargs):
  120. """ Create an API object. """
  121. self._setuplogging()
  122. self.set_log_level(log_level)
  123. self.server = server
  124. self.url = server + '/api_jsonrpc.php'
  125. self.proto = self.server.split("://")[0]
  126. #self.proto=proto
  127. self.httpuser = user
  128. self.httppasswd = passwd
  129. self.timeout = timeout
  130. self.usergroup = ZabbixAPISubClass(self, dict({"prefix": "usergroup"}, **kwargs))
  131. self.user = ZabbixAPISubClass(self, dict({"prefix": "user"}, **kwargs))
  132. self.host = ZabbixAPISubClass(self, dict({"prefix": "host"}, **kwargs))
  133. self.item = ZabbixAPISubClass(self, dict({"prefix": "item"}, **kwargs))
  134. self.hostgroup = ZabbixAPISubClass(self, dict({"prefix": "hostgroup"}, **kwargs))
  135. self.application = ZabbixAPISubClass(self, dict({"prefix": "application"}, **kwargs))
  136. self.trigger = ZabbixAPISubClass(self, dict({"prefix": "trigger"}, **kwargs))
  137. self.template = ZabbixAPISubClass(self, dict({"prefix": "template"}, **kwargs))
  138. self.action = ZabbixAPISubClass(self, dict({"prefix": "action"}, **kwargs))
  139. self.alert = ZabbixAPISubClass(self, dict({"prefix": "alert"}, **kwargs))
  140. self.info = ZabbixAPISubClass(self, dict({"prefix": "info"}, **kwargs))
  141. self.event = ZabbixAPISubClass(self, dict({"prefix": "event"}, **kwargs))
  142. self.graph = ZabbixAPISubClass(self, dict({"prefix": "graph"}, **kwargs))
  143. self.graphitem = ZabbixAPISubClass(self, dict({"prefix": "graphitem"}, **kwargs))
  144. self.map = ZabbixAPISubClass(self, dict({"prefix": "map"}, **kwargs))
  145. self.screen = ZabbixAPISubClass(self, dict({"prefix": "screen"}, **kwargs))
  146. self.script = ZabbixAPISubClass(self, dict({"prefix": "script"}, **kwargs))
  147. self.usermacro = ZabbixAPISubClass(self, dict({"prefix": "usermacro"}, **kwargs))
  148. self.map = ZabbixAPISubClass(self, dict({"prefix": "map"}, **kwargs))
  149. self.drule = ZabbixAPISubClass(self, dict({"prefix": "drule"}, **kwargs))
  150. self.history = ZabbixAPISubClass(self, dict({"prefix": "history"}, **kwargs))
  151. self.maintenance = ZabbixAPISubClass(self, dict({"prefix": "maintenance"}, **kwargs))
  152. self.proxy = ZabbixAPISubClass(self, dict({"prefix": "proxy"}, **kwargs))
  153. self.apiinfo = ZabbixAPISubClass(self, dict({"prefix": "apiinfo"}, **kwargs))
  154. self.id = 0
  155. self.r_query = deque([], maxlen=r_query_len)
  156. self.debug(logging.INFO, "url: " + self.url)
  157. def _setuplogging(self):
  158. self.logger = logging.getLogger("zabbix_api.%s" % self.__class__.__name__)
  159. def set_log_level(self, level):
  160. self.debug(logging.INFO, "Set logging level to %d" % level)
  161. self.logger.setLevel(level)
  162. def recent_query(self):
  163. """
  164. return recent query
  165. """
  166. return list(self.r_query)
  167. def debug(self, level, var="", msg=None):
  168. strval = str(level) + ": "
  169. if msg:
  170. strval = strval + str(msg)
  171. if var != "":
  172. strval = strval + str(var)
  173. self.logger.log(level, strval)
  174. def json_obj(self, method, params={}):
  175. obj = {'jsonrpc': '2.0',
  176. 'method': method,
  177. 'params': params,
  178. 'auth': self.auth,
  179. 'id': self.id
  180. }
  181. self.debug(logging.DEBUG, "json_obj: " + str(obj))
  182. return json.dumps(obj)
  183. def login(self, user='', password='', save=True):
  184. if user != '':
  185. l_user = user
  186. l_password = password
  187. if save:
  188. self.__username__ = user
  189. self.__password__ = password
  190. elif self.__username__ != '':
  191. l_user = self.__username__
  192. l_password = self.__password__
  193. else:
  194. raise ZabbixAPIException("No authentication information available.")
  195. # don't print the raw password.
  196. hashed_pw_string = "md5(" + hashlib.md5(l_password.encode('utf-8')).hexdigest() + ")"
  197. self.debug(logging.DEBUG, "Trying to login with %s:%s" % \
  198. (repr(l_user), repr(hashed_pw_string)))
  199. obj = self.json_obj('user.authenticate', {'user': l_user,
  200. 'password': l_password})
  201. result = self.do_request(obj)
  202. self.auth = result['result']
  203. def test_login(self):
  204. if self.auth != '':
  205. obj = self.json_obj('user.checkAuthentication', {'sessionid': self.auth})
  206. result = self.do_request(obj)
  207. if not result['result']:
  208. self.auth = ''
  209. return False # auth hash bad
  210. return True # auth hash good
  211. else:
  212. return False
  213. def do_request(self, json_obj):
  214. headers = {'Content-Type': 'application/json-rpc',
  215. 'User-Agent': 'python/zabbix_api'}
  216. if self.httpuser:
  217. self.debug(logging.INFO, "HTTP Auth enabled")
  218. auth = 'Basic ' + string.strip(base64.encodestring(self.httpuser + ':' + self.httppasswd))
  219. headers['Authorization'] = auth
  220. self.r_query.append(str(json_obj))
  221. self.debug(logging.INFO, "Sending: " + str(json_obj))
  222. self.debug(logging.DEBUG, "Sending headers: " + str(headers))
  223. request = urllib2.Request(url=self.url, data=json_obj.encode('utf-8'), headers=headers)
  224. if self.proto == "https":
  225. https_handler = urllib2.HTTPSHandler(debuglevel=0)
  226. opener = urllib2.build_opener(https_handler)
  227. elif self.proto == "http":
  228. http_handler = urllib2.HTTPHandler(debuglevel=0)
  229. opener = urllib2.build_opener(http_handler)
  230. else:
  231. raise ZabbixAPIException("Unknow protocol %s" % self.proto)
  232. urllib2.install_opener(opener)
  233. try:
  234. response = opener.open(request, timeout=self.timeout)
  235. self.debug(logging.INFO, "Response Code: " + str(response.code))
  236. except urllib2.URLError:
  237. #raise ZabbixAPIException("Could not open URL <%s>" % response.url)
  238. raise ZabbixAPIException("Could not open URL")
  239. # NOTE: Getting a 412 response code means the headers are not in the
  240. # list of allowed headers.
  241. if response.code != 200:
  242. raise ZabbixAPIException("HTTP ERROR %s: %s"
  243. % (response.status, response.reason))
  244. reads = response.read()
  245. if len(reads) == 0:
  246. raise ZabbixAPIException("Received zero answer")
  247. try:
  248. jobj = json.loads(reads.decode('utf-8'))
  249. except ValueError as msg:
  250. print ("unable to decode. returned string: %s" % reads)
  251. sys.exit(-1)
  252. self.debug(logging.DEBUG, "Response Body: " + str(jobj))
  253. self.id += 1
  254. if 'error' in jobj: # some exception
  255. msg = "Error %s: %s, %s while sending %s" % (jobj['error']['code'],
  256. jobj['error']['message'], jobj['error']['data'], str(json_obj))
  257. if re.search(".*already\sexists.*", jobj["error"]["data"], re.I): # already exists
  258. raise Already_Exists(msg, jobj['error']['code'])
  259. else:
  260. raise ZabbixAPIException(msg, jobj['error']['code'])
  261. return jobj
  262. def logged_in(self):
  263. if self.auth != '':
  264. return True
  265. return False
  266. def api_version(self, **options):
  267. self.__checkauth__()
  268. obj = self.do_request(self.json_obj('APIInfo.version', options))
  269. return obj['result']
  270. def __checkauth__(self):
  271. if not self.logged_in():
  272. raise ZabbixAPIException("Not logged in.")
  273. class ZabbixAPISubClass(ZabbixAPI):
  274. """ wrapper class to ensure all calls go through the parent object """
  275. parent = None
  276. data = None
  277. def __init__(self, parent, data, **kwargs):
  278. self._setuplogging()
  279. self.debug(logging.INFO, "Creating %s" % self.__class__.__name__)
  280. self.data = data
  281. self.parent = parent
  282. # Save any extra info passed in
  283. for key, val in kwargs.items():
  284. setattr(self, key, val)
  285. self.debug(logging.WARNING, "Set %s:%s" % (repr(key), repr(val)))
  286. def __getattr__(self, name):
  287. def method(*opts):
  288. return self.universal("%s.%s" % (self.data["prefix"], name), opts[0])
  289. return method
  290. def __checkauth__(self):
  291. self.parent.__checkauth__()
  292. def do_request(self, req):
  293. return self.parent.do_request(req)
  294. def json_obj(self, method, param):
  295. return self.parent.json_obj(method, param)
  296. @dojson2
  297. @checkauth
  298. def universal(self, **opts):
  299. return opts