Advertisement
Guest User

Untitled

a guest
Apr 14th, 2017
422
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.94 KB | None | 0 0
  1. root@central-monitoring:/usr/lib/zabbix/alertscripts# cat zbxtg.py
  2. #!/usr/bin/env python
  3. # coding: utf-8
  4.  
  5. import sys
  6. import os
  7. import time
  8. import random
  9. import requests
  10. import json
  11. import re
  12. import stat
  13. from os.path import dirname
  14. import zbxtg_settings
  15.  
  16.  
  17. class TelegramAPI():
  18.     tg_url_bot_general = "https://api.telegram.org/bot"
  19.  
  20.     def http_get(self, url):
  21.         res = requests.get(url, proxies=self.proxies)
  22.         answer = res.text
  23.         answer_json = json.loads(answer.decode('utf8'))
  24.         return answer_json
  25.  
  26.     def __init__(self, key):
  27.         self.debug = False
  28.         self.key = key
  29.         self.proxies = {}
  30.         self.type = "private"  
  31.         self.markdown = False
  32.         self.html = False
  33.         self.disable_web_page_preview = False
  34.         self.disable_notification = False
  35.         self.reply_to_message_id = 0
  36.         self.tmp_uids = None
  37.  
  38.     def get_me(self):
  39.         url = self.tg_url_bot_general + self.key + "/getMe"
  40.         me = self.http_get(url)
  41.         return me
  42.  
  43.     def get_updates(self):
  44.         url = self.tg_url_bot_general + self.key + "/getUpdates"
  45.         if self.debug:
  46.             print_message(url)
  47.         updates = self.http_get(url)
  48.         if self.debug:
  49.             print_message("Content of /getUpdates:")
  50.             print_message(updates)
  51.         if not updates["ok"]:
  52.             print_message(updates)
  53.             return updates
  54.         else:
  55.             return updates
  56.  
  57.     def send_message(self, to, message):
  58.         url = self.tg_url_bot_general + self.key + "/sendMessage"
  59.         message = "\n".join(message)
  60.         params = {"chat_id": to, "text": message, "disable_web_page_preview": self.disable_web_page_preview,
  61.                   "disable_notification": self.disable_notification}
  62.         if self.reply_to_message_id:
  63.             params["reply_to_message_id"] = self.reply_to_message_id
  64.         if self.markdown or self.html:
  65.             parse_mode = "HTML"
  66.             if self.markdown:
  67.                 parse_mode = "Markdown"
  68.             params["parse_mode"] = parse_mode
  69.         if self.debug:
  70.             print_message("Trying to /sendMessage:")
  71.             print_message(url)
  72.             print_message("post params: " + str(params))
  73.         res = requests.post(url, params=params, proxies=self.proxies)
  74.         answer = res.text
  75.         answer_json = json.loads(answer.decode('utf8'))
  76.         if not answer_json["ok"]:
  77.             print_message(answer_json)
  78.             return answer_json
  79.         else:
  80.             return answer_json
  81.  
  82.     def send_photo(self, to, message, path):
  83.         url = self.tg_url_bot_general + self.key + "/sendPhoto"
  84.         message = "\n".join(message)
  85.         params = {"chat_id": to, "caption": message, "disable_notification": self.disable_notification}
  86.         if self.reply_to_message_id:
  87.             params["reply_to_message_id"] = self.reply_to_message_id
  88.         files = {"photo": open(path, 'rb')}
  89.         if self.debug:
  90.             print_message("Trying to /sendPhoto:")
  91.             print_message(url)
  92.             print_message(params)
  93.             print_message("files: " + str(files))
  94.         res = requests.post(url, params=params, files=files, proxies=self.proxies)
  95.         answer = res.text
  96.         answer_json = json.loads(answer.decode('utf8'))
  97.         if not answer_json["ok"]:
  98.             print_message(answer_json)
  99.             return answer_json
  100.         else:
  101.             return answer_json
  102.  
  103.     def get_uid(self, name):
  104.         uid = 0
  105.         if self.debug:
  106.             print_message("Getting uid from /getUpdates...")
  107.         updates = self.get_updates()
  108.         for m in updates["result"]:
  109.             if "message" in m:
  110.                 chat = m["message"]["chat"]
  111.             elif "edited_message" in m:
  112.                 chat = m["edited_message"]["chat"]
  113.             if chat["type"] == self.type == "private":
  114.                 if "username" in chat:
  115.                     if chat["username"] == name:
  116.                         uid = chat["id"]
  117.             if (chat["type"] == "group" or chat["type"] == "supergroup") and self.type == "group":
  118.                 if "title" in chat:
  119.                     if chat["title"] == name.decode("utf-8"):
  120.                         uid = chat["id"]
  121.         return uid
  122.  
  123.     def error_need_to_contact(self, to):
  124.         if self.type == "private":
  125.             print_message("User '{0}' needs to send some text bot in private".format(to))
  126.         if self.type == "group":
  127.             print_message("You need to mention your bot in '{0}' group chat (i.e. type @YourBot)".format(to))
  128.  
  129.     def update_cache_uid(self, name, uid, message="Add new string to cache file"):
  130.         cache_string = "{0};{1};{2}\n".format(name, self.type, str(uid).rstrip())
  131.         # FIXME
  132.         if self.debug:
  133.             print_message("{0}: {1}".format(message, cache_string))
  134.         with open(self.tmp_uids, "a") as cache_file_uids:
  135.             cache_file_uids.write(cache_string)
  136.  
  137.     def get_uid_from_cache(self, name):
  138.         uid = 0
  139.         if os.path.isfile(self.tmp_uids):
  140.             with open(self.tmp_uids, 'r') as cache_file_uids:
  141.                 cache_uids_old = cache_file_uids.readlines()
  142.  
  143.             for u in cache_uids_old:
  144.                 u_splitted = u.split(";")
  145.                 if name == u_splitted[0] and self.type == u_splitted[1]:
  146.                     uid = u_splitted[2]
  147.  
  148.         return uid
  149.  
  150.  
  151. class ZabbixAPI():
  152.     def __init__(self, server, username, password):
  153.         self.debug = False
  154.         self.server = server
  155.         self.username = username
  156.         self.password = password
  157.         self.proxies = {}
  158.         self.verify = True
  159.         self.cookie = None
  160.  
  161.     def login(self):
  162.  
  163.         if not self.verify:
  164.             requests.packages.urllib3.disable_warnings()
  165.  
  166.         data_api = {"name": self.username, "password": self.password, "enter": "Sign in"}
  167.         req_cookie = requests.post(self.server + "/", data=data_api, proxies=self.proxies, verify=self.verify)
  168.         cookie = req_cookie.cookies
  169.         if len(req_cookie.history) > 1 and req_cookie.history[0].status_code == 302:
  170.             print_message("probably the server in your config file has not full URL (for example "
  171.                           "'{0}' instead of '{1}')".format(self.server, self.server + "/zabbix"))
  172.         if not cookie:
  173.             print_message("authorization has failed, url: {0}".format(self.server + "/"))
  174.             cookie = None
  175.  
  176.         self.cookie = cookie
  177.  
  178.     def graph_get(self, itemid, period, title, width, height, tmp_dir):
  179.         file_img = tmp_dir + "/{0}.png".format(itemid)
  180.  
  181.         title = requests.utils.quote(title)
  182.  
  183.         zbx_img_url = self.server + "/chart3.php?period={1}&name={2}" \
  184.                                     "&width={3}&height={4}&graphtype=0&legend=1" \
  185.                                     "&items[0][itemid]={0}&items[0][sortorder]=0" \
  186.                                     "&items[0][drawtype]=5&items[0][color]=00CC00".format(itemid, period, title,
  187.                                                                                           width, height)
  188.         if self.debug:
  189.             print_message(zbx_img_url)
  190.         res = requests.get(zbx_img_url, cookies=self.cookie, proxies=self.proxies, verify=self.verify)
  191.         res_code = res.status_code
  192.         if res_code == 404:
  193.             print_message("can't get image from '{0}'".format(zbx_img_url))
  194.             return False
  195.         res_img = res.content
  196.         with open(file_img, 'wb') as fp:
  197.             fp.write(res_img)
  198.         return file_img
  199.  
  200.     def api_test(self):
  201.         headers = {'Content-type': 'application/json'}
  202.         api_data = json.dumps({"jsonrpc": "2.0", "method": "user.login", "params":
  203.                               {"user": self.username, "password": self.password}, "id": 1})
  204.         api_url = self.server + "/api_jsonrpc.php"
  205.         api = requests.post(api_url, data=api_data, proxies=self.proxies, headers=headers)
  206.         return api.text
  207.  
  208.  
  209. def print_message(string):
  210.     string = str(string) + "\n"
  211.     filename = sys.argv[0].split("/")[-1]
  212.     sys.stderr.write(filename + ": " + string)
  213.  
  214.  
  215. def list_cut(elements, symbols_limit):
  216.     symbols_count = symbols_count_now = 0
  217.     elements_new = []
  218.     element_last = None
  219.     element_last_list = []
  220.     for e in elements:
  221.         symbols_count_now = symbols_count + len(e)
  222.         if symbols_count_now > symbols_limit:
  223.             limit_idx = symbols_limit - symbols_count
  224.             e_list = list(e)
  225.             for idx, ee in enumerate(e_list):
  226.                 if idx < limit_idx:
  227.                     element_last_list.append(ee)
  228.                 else:
  229.                     break
  230.             break
  231.         else:
  232.             symbols_count = symbols_count_now + 1
  233.             elements_new.append(e)
  234.     if symbols_count_now < symbols_limit:
  235.         return elements, False
  236.     else:
  237.         element_last = "".join(element_last_list)
  238.         elements_new.append(element_last)
  239.         return elements_new, True
  240.  
  241.  
  242. def main():
  243.  
  244.     tmp_dir = zbxtg_settings.zbx_tg_tmp_dir
  245.  
  246.     tmp_cookie = tmp_dir + "/cookie.py.txt"
  247.     tmp_uids = tmp_dir + "/uids.txt"
  248.     tmp_need_update = False  # do we need to update cache file with uids or not
  249.  
  250.     rnd = random.randint(0, 999)
  251.     ts = time.time()
  252.     hash_ts = str(ts) + "." + str(rnd)
  253.  
  254.     log_file = "/dev/null"
  255.  
  256.     zbx_to = sys.argv[1]
  257.     zbx_subject = sys.argv[2]
  258.     zbx_body = sys.argv[3]
  259.  
  260.     tg = TelegramAPI(key=zbxtg_settings.tg_key)
  261.  
  262.     tg.tmp_uids = tmp_uids
  263.  
  264.     if zbxtg_settings.proxy_to_tg:
  265.         tg.proxies = {
  266.             "http": "http://{0}/".format(zbxtg_settings.proxy_to_tg),
  267.             "https": "https://{0}/".format(zbxtg_settings.proxy_to_tg)
  268.             }
  269.  
  270.     zbx = ZabbixAPI(server=zbxtg_settings.zbx_server, username=zbxtg_settings.zbx_api_user,
  271.                     password=zbxtg_settings.zbx_api_pass)
  272.  
  273.     if zbxtg_settings.proxy_to_zbx:
  274.         zbx.proxies = {
  275.             "http": "http://{0}/".format(zbxtg_settings.proxy_to_zbx),
  276.             "https": "https://{0}/".format(zbxtg_settings.proxy_to_zbx)
  277.             }
  278.  
  279.     try:
  280.         zbx_api_verify = zbxtg_settings.zbx_api_verify
  281.         zbx.verify = zbx_api_verify
  282.     except:
  283.         pass
  284.  
  285.     zbxtg_body = (zbx_subject + "\n" + zbx_body).splitlines()
  286.     zbxtg_body_text = []
  287.  
  288.     settings = {
  289.         "zbxtg_itemid": "0",  # itemid for graph
  290.         "zbxtg_title": None,  # title for graph
  291.         "zbxtg_image_period": "3600",
  292.         "zbxtg_image_width": "900",
  293.         "zbxtg_image_height": "200",
  294.         "tg_method_image": False,  # if True - default send images, False - send text
  295.         "tg_chat": False,  # send message to chat or in private
  296.         "tg_group": False,  # send message to chat or in private
  297.         "is_debug": False,
  298.         "is_channel": False,
  299.         "disable_web_page_preview": False,
  300.     }
  301.     settings_description = {
  302.         "itemid": {"name": "zbxtg_itemid", "type": "int"},
  303.         "title": {"name": "zbxtg_title", "type": "str"},
  304.         "graphs_period": {"name": "zbxtg_image_period", "type": "int"},
  305.         "graphs_width": {"name": "zbxtg_image_width", "type": "int"},
  306.         "graphs_height": {"name": "zbxtg_image_height", "type": "int"},
  307.         "graphs": {"name": "tg_method_image", "type": "bool"},
  308.         "chat": {"name": "tg_chat", "type": "bool"},
  309.         "group": {"name": "tg_group", "type": "bool"},
  310.         "debug": {"name": "is_debug", "type": "bool"},
  311.         "channel": {"name": "is_channel", "type": "bool"},
  312.         "disable_web_page_preview": {"name": "disable_web_page_preview", "type": "bool"},
  313.     }
  314.  
  315.     for line in zbxtg_body:
  316.         if line.find(zbxtg_settings.zbx_tg_prefix) > -1:
  317.             setting = re.split("[\s\:\=]+", line, maxsplit=1)
  318.             key = setting[0].replace(zbxtg_settings.zbx_tg_prefix + ";", "")
  319.             if len(setting) > 1 and len(setting[1]) > 0:
  320.                 value = setting[1]
  321.             else:
  322.                 value = True
  323.             if key in settings_description:
  324.                 settings[settings_description[key]["name"]] = value
  325.         else:
  326.             zbxtg_body_text.append(line)
  327.  
  328.     tg_method_image = bool(settings["tg_method_image"])
  329.     tg_chat = bool(settings["tg_chat"])
  330.     tg_group = bool(settings["tg_group"])
  331.     is_debug = bool(settings["is_debug"])
  332.     is_channel = bool(settings["is_channel"])
  333.     disable_web_page_preview = bool(settings["disable_web_page_preview"])
  334.  
  335.     if sys.argv[0].split("/")[-1] == "zbxtg_group.py" or "--group" in sys.argv or tg_chat or tg_group:
  336.         tg_chat = True
  337.         tg_group = True
  338.         tg.type = "group"
  339.  
  340.     if "--debug" in sys.argv or is_debug:
  341.         is_debug = True
  342.         tg.debug = True
  343.         zbx.debug = True
  344.         print_message(tg.get_me())
  345.         print_message("Cache file with uids: " + tg.tmp_uids)
  346.         log_file = tmp_dir + ".debug." + hash_ts + ".log"
  347.         #print_message(log_file)
  348.  
  349.     if "--markdown" in sys.argv:
  350.         tg.markdown = True
  351.  
  352.     if "--html" in sys.argv:
  353.         tg.html = True
  354.  
  355.     if "--channel" in sys.argv or is_channel:
  356.         tg.type = "channel"
  357.  
  358.     if "--disable_web_page_preview" in sys.argv or disable_web_page_preview:
  359.         if is_debug:
  360.             print_message("'disable_web_page_preview' option has been enabled")
  361.         tg.disable_web_page_preview = True
  362.  
  363.     if not os.path.isdir(tmp_dir):
  364.         if is_debug:
  365.             print_message("Tmp dir doesn't exist, creating new one...")
  366.         try:
  367.             os.makedirs(tmp_dir)
  368.             open(tg.tmp_uids, "a").close()
  369.             os.chmod(tmp_dir, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
  370.             os.chmod(tg.tmp_uids, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
  371.         except:
  372.             tmp_dir = "/tmp"
  373.         if is_debug:
  374.             print_message("Using {0} as a temporary dir".format(tmp_dir))
  375.  
  376.     uid = None
  377.  
  378.     if tg.type == "channel":
  379.         uid = zbx_to
  380.     else:
  381.         zbx_to = zbx_to.replace("@", "")
  382.  
  383.     if not uid:
  384.         uid = tg.get_uid_from_cache(zbx_to)
  385.  
  386.     if not uid:
  387.         uid = tg.get_uid(zbx_to)
  388.         if uid:
  389.             tmp_need_update = True
  390.     if not uid:
  391.         tg.error_need_to_contact(zbx_to)
  392.         sys.exit(1)
  393.  
  394.     if tmp_need_update:
  395.         tg.update_cache_uid(zbx_to, str(uid).rstrip())
  396.  
  397.     if is_debug:
  398.         print_message("Telegram uid of {0} '{1}': {2}".format(tg.type, zbx_to, uid))
  399.  
  400.     # add signature, turned off by default, you can turn it on in config
  401.     try:
  402.         if zbxtg_settings.zbx_tg_signature:
  403.             zbxtg_body_text.append("--")
  404.             zbxtg_body_text.append(zbxtg_settings.zbx_server)
  405.     except:
  406.         pass
  407.  
  408.    
  409.     if hasattr(zbxtg_settings, "emoji_map"):
  410.         zbxtg_body_text_emoji_support = []
  411.         for l in zbxtg_body_text:
  412.             l_new = l
  413.             for k, v in zbxtg_settings.emoji_map.iteritems():
  414.                 l_new = l_new.replace("{{" + k + "}}", v)
  415.             zbxtg_body_text_emoji_support.append(l_new)
  416.         zbxtg_body_text = zbxtg_body_text_emoji_support
  417.  
  418.     if not tg_method_image:
  419.         result = tg.send_message(uid, zbxtg_body_text)
  420.         if not result["ok"]:
  421.             if result["description"].find("migrated") > -1 and result["description"].find("supergroup") > -1:
  422.  
  423.                 migrate_to_chat_id = result["parameters"]["migrate_to_chat_id"]
  424.                 tg.update_cache_uid(zbx_to, migrate_to_chat_id, message="Group chat is migrated to supergroup, updating cache file")
  425.                 uid = migrate_to_chat_id
  426.                 result = tg.send_message(uid, zbxtg_body_text)
  427.     else:
  428.         zbx.login()
  429.         if not zbx.cookie:
  430.             print_message("Login to Zabbix web UI has failed, check manually...")
  431.         else:
  432.             zbxtg_file_img = zbx.graph_get(settings["zbxtg_itemid"], settings["zbxtg_image_period"],
  433.                                            settings["zbxtg_title"], settings["zbxtg_image_width"],
  434.                                            settings["zbxtg_image_height"], tmp_dir)
  435.             #zbxtg_body_text, is_modified = list_cut(zbxtg_body_text, 200)
  436.             result = tg.send_message(uid, zbxtg_body_text)
  437.             message_id = result["result"]["message_id"]
  438.             tg.reply_to_message_id = message_id
  439.             tg.disable_notification = True
  440.             if not zbxtg_file_img:
  441.                 tg.send_message(uid, ["Can't get graph image, check script manually, see logs, or disable graphs"])
  442.                 print_message("Can't get image, check URL manually")
  443.             else:
  444.  
  445.                 zbxtg_body_text = ""
  446.                 """
  447.                if is_modified:
  448.                    print_message("probably you will see MEDIA_CAPTION_TOO_LONG error, "
  449.                                  "the message has been cut to 200 symbols")
  450.                                                  """
  451.                 if tg.send_photo(uid, zbxtg_body_text, zbxtg_file_img):
  452.                     os.remove(zbxtg_file_img)
  453.  
  454.  
  455. if __name__ == "__main__"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement