Monitorando salas Zadarma Zabbix

Eu ofereço um modelo pronto para o Zabbix e um script Python para detectar automaticamente novos números de provedores do Zadarma (novos, no sentido dos números que você comprou).

O modelo possui vários gatilhos e informações básicas sobre os quartos. O script funciona com a API Zadarma ou o banco de dados MySQL.

Para trabalhar com o MySQL, é necessário colocar os dados com antecedência na coroa ou diretamente do dialplan usando um script separado.

Ambos os scripts sob o corte.

zadarma_number.py
O script deve ser colocado no diretório com scripts para o agente zabbiz, eu tenho

/etc/zabbix/scripts/ 

Além disso, conceda o direito de executar e, apenas no caso, altere o proprietário e o grupo do zabbix:

 chmod +x /etc/zabbix/scripts/zadarma_number.py chown zabbix:zabbix /etc/zabbix/scripts/zadarma_number.py 

 #! /usr/bin/env python3 import json import pymysql import argparse import sys import base64 import hmac import requests from hashlib import sha1, md5 from collections import OrderedDict from urllib.parse import urlencode api_key = '222c2fd22c2d2222a2b2' secret_key = '2a2f2222cee2222f2222' database_address = '192.168.10.18' database_name = 'asterisk' database_user = 'asterisk' database_password = 'dFgXuasfvgas45hAkEb2' zadarma_api_url = 'http://api.zadarma.com' monthly_fee_all = 0 def sql_result(sql): cursor.execute(sql) data = cursor.fetchall() return data def str_for_json(data): json_data = [] for result in data: json_data.append(dict(zip(['{#NUMBER}'], result))) json_data = ({"data":json_data}) return json.dumps(json_data) # return json.dumps(json_data) def createParser(): parser = argparse.ArgumentParser( prog='Zadarma for Zabbix', description='''       Zadarma       zabbiz .''', epilog='''(c)  2018.  ,  ,       .''' ) parser.add_argument('-l', '--allnumbers', action='store_true', help='"Show all found phone numbers in a format suitable for zabbix. ' ' Running a script without parameters (or with the -f option) leads to the same result."') parser.add_argument('-n', '--number', help = '"Phone number and -s or -S or -g or -e or -d or -m or -a "', metavar = 'phone number') parser.add_argument('-S', '--status', action='store_true') parser.add_argument('-g', '--start_date', action='store_true') parser.add_argument('-e', '--stop_date', action='store_true') parser.add_argument('-d', '--description', action='store_true') parser.add_argument('-s', '--sip', action='store_true', help='"can be used in combination with "-c""') parser.add_argument('-m', '--monthly_fee', action='store_true', help='"The amount required to renew a phone number or all phone numbers"') parser.add_argument('-a', '--autorenew', action='store_true') parser.add_argument('-b', '--balance', action='store_true', help='All balance numbers') parser.add_argument('-f', '--force_API', action='store_true',default=False, help = '"Force the use of api, the database is ignored"') parser.add_argument('-c', '--cut', type=int, default=0, help='''Used only in conjunction with "-s" 0 - The whole line, 1- Part of the string before "@", 2 - Part of the line after "@"''', metavar='[0,1,2] or none') return parser def api_zapros(method,data): if not data: data = {'format': 'json'} sorted_dict_params = OrderedDict(sorted(data.items())) query_string = urlencode(sorted_dict_params) h = md5(query_string.encode('utf8')).hexdigest() data = method + query_string + h hashed = hmac.new(secret_key.encode('utf8'), data.encode('utf8'), sha1) auth = api_key + ':' + base64.b64encode(bytes(hashed.hexdigest(), 'utf8')).decode() headers = {'User-Agent': '-', 'Authorization': auth} url = zadarma_api_url + method + '?' + query_string; r = requests.get(url, headers=headers) r.raise_for_status() return json.loads(r.text) def no_sql(*args): number = args[0] parametr = args[1] for number_string in numbers_result['info']: if number_string['number'] == number: if number_string[parametr] == 'true' or number_string[parametr] == 'on': return '0' elif number_string[parametr] == 'false' or number_string[parametr] == 'off': return '1' else: return number_string[parametr] def zapros(*args): if namespace.force_API: return no_sql(namespace.number,args[0]) else: return sql_result(sql)[0][0] parser = createParser() namespace = parser.parse_args(sys.argv[1:]) if not namespace.force_API: try: db = pymysql.connect(database_address, database_user, database_password, database_name) cursor = db.cursor() except pymysql.Error as e: print('\n\t!!!!!!!!!!!SQL no connect!!!!!!!!!!!\n') print(e) exit(1) else: try: numbers_result = api_zapros('/v1/direct_numbers/', '') balance_info = api_zapros('/v1/info/balance/', '') except Exception as e: print('Error connect API zadarma') exit(1) # print('namespace', namespace) if namespace.number and namespace.status: sql = "SELECT status FROM zadarma_numbers WHERE number = %s;" % (namespace.number) print(zapros('status')) elif namespace.number and namespace.start_date: sql = "SELECT start_date FROM zadarma_numbers WHERE number = %s;" % (namespace.number) print(zapros('start_date')) elif namespace.number and namespace.stop_date: sql = "SELECT stop_date FROM zadarma_numbers WHERE number = %s;" % (namespace.number) print(zapros('stop_date')) elif namespace.number and namespace.autorenew: sql = "SELECT autorenew FROM zadarma_numbers WHERE number = %s;" % (namespace.number) print(zapros('autorenew')) elif namespace.number and namespace.description: sql = "SELECT description FROM zadarma_numbers WHERE number = %s;" % (namespace.number) print(zapros('description')) elif namespace.number and namespace.sip: sql = "SELECT sip FROM zadarma_numbers WHERE number = %s;" % (namespace.number) if namespace.cut == 0: print(zapros('sip')) if namespace.cut == 1: try: print(zapros('sip').split('@')[0]) except IndexError: print(zapros('sip')) if namespace.cut == 2: try: print(zapros('sip').split('@')[1]) except IndexError: print(zapros('sip')) elif namespace.number and namespace.monthly_fee: sql = "SELECT monthly_fee FROM zadarma_numbers WHERE number = %s;" % (namespace.number) print(zapros('monthly_fee')) else: if namespace.number: # sql = "SELECT * FROM zadarma_numbers WHERE number = %s;" % (namespace.number) # print(zapros(namespace.number)) print(namespace.number, 'there are not enough arguments or incorrect combination of arguments') sys.exit(1) elif namespace.balance: if namespace.force_API: balance = balance_info['balance'] print(balance) else: print(sql_result('SELECT balance FROM zadarma_balance;')[0][0]) elif namespace.monthly_fee: if namespace.force_API: for result in numbers_result['info']: monthly_fee_all = monthly_fee_all + result['monthly_fee'] print(monthly_fee_all) else: print(sql_result('SELECT monthly_fee FROM zadarma_balance;')[0][0]) elif namespace.allnumbers: if namespace.force_API: json_data = [] for result in numbers_result['info']: print(result['number']) json_data.append(dict(zip(['{#NUMBER}'], [result['number']]))) json_data = ({"data": json_data}) print('jkgkgliuui',json.dumps(json_data)) else: data = sql_result('SELECT number FROM zadarma_numbers WHERE stop_date > date') print(str_for_json(data)) else: if namespace.force_API: json_data = [] for result in numbers_result['info']: json_data.append(dict(zip(['{#NUMBER}'], [result['number']]))) json_data = ({"data": json_data}) print(json.dumps(json_data)) else: data = sql_result('SELECT number FROM zadarma_numbers WHERE stop_date > date') print(str_for_json(data)) if not namespace.force_API: db.close() 


Teoricamente, trabalhar com um determinado banco de dados pode se mostrar mais relevante, pois um script para adicionar informações pode ser executado após cada chamada. Portanto, as informações no banco de dados podem se mostrar um pouco mais relevantes do que o trabalho direto com a API diretamente do Zabbix.

No modelo do Zabbix, a macro {$ FORCE_API} força o script a trabalhar com a API do Zadarma.
A macro {$ CUT} é usada para dividir a sequência de solicitação SIP-URI em partes antes de "@" e depois.

O script tem várias chaves para executar.

Sem as teclas ou com a opção -l, o script retornará uma lista de números no formato json, adequada para a detecção automática de números no zabbix.

Ajuda para chaves de script:
uso: Zadarma para Zabbix [-h] [-l] [-n número de telefone] [-S] [-g] [-e] [-d] [-s]
[-m] [-a] [-b] [-f] [-c [0,1,2] ou nenhum]

Este programa foi desenvolvido para monitorar os números de provedores da Zadarma e
originalmente concebido como um script para o agente zabbiz.

 optional arguments: -h, --help show this help message and exit -l, --allnumbers "Show all found phone numbers in a format suitable for zabbix. Running a script without parameters (or with the -f option) leads to the same result." -n phone number, --number phone number "Phone number and -s or -S or -g or -e or -d or -m or -a " -S, --status -g, --start_date -e, --stop_date -d, --description -s, --sip "can be used in combination with "-c"" -m, --monthly_fee "The amount required to renew a phone number or all phone numbers" -a, --autorenew -b, --balance All balance numbers -f, --force_API "Force the use of api, the database is ignored" -c [0,1,2] or none, --cut [0,1,2] or none Used only in conjunction with "-s" 0 - The whole line, 1- Part of the string before "@", 2 - Part of the line after "@" 


As teclas "-S, -s, -g, -e, -d, -a" são usadas apenas em combinação com um número
A opção -m pode ser usada com ou sem um número
Tecla -b, apenas sem número
A opção -c apenas com a opção -s
A opção -f força o uso da API, sem ela, uma solicitação é enviada ao banco de dados e pode ser usada com qualquer opção.

Segundo script:

Script API_to_MySql
Portanto, dê o direito de executar:

 chmod +x ./main.py 

Como chamar o script e onde colocá-lo, decida por si mesmo.

 #! /usr/bin/env python3 from hashlib import sha1, md5 from collections import OrderedDict from urllib.parse import urlencode import hmac import requests import base64 import json import pymysql api_key = '222c2fd22c2d2222a2b2' secret_key = '2a2f2222cee2222f2222' database_address = '192.168.10.18' database_name = 'asterisk' database_user = 'asterisk' database_password = 'dFgXuasfvgas45hAkEb2' zadarma_api_url = 'http://api.zadarma.com' monthly_fee_all = 0 debug = True # debug = False db = pymysql.connect(database_address, database_user, database_password, database_name) cursor = db.cursor() def sql_insert(): sql = "REPLACE zadarma_numbers (id, date, number, number_name, description, sip, start_date, stop_date, monthly_fee, status, channels, autorenew) \ VALUES (NULL, UTC_TIMESTAMP(), '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');" % \ (number,number_name, description, sip, start_date, stop_date, monthly_fee, status, channels, autorenew) try: # Execute the SQL command cursor.execute(sql) # Commit your changes in the database db.commit() except: # Rollback in case there is any error db.rollback() def zapros(method,data): if not data: data = {'format': 'json'} sorted_dict_params = OrderedDict(sorted(data.items())) query_string = urlencode(sorted_dict_params) h = md5(query_string.encode('utf8')).hexdigest() data = method + query_string + h hashed = hmac.new(secret_key.encode('utf8'), data.encode('utf8'), sha1) auth = api_key + ':' + base64.b64encode(bytes(hashed.hexdigest(), 'utf8')).decode() headers = {'User-Agent': '-', 'Authorization': auth} url = zadarma_api_url + method + '?' + query_string; r = requests.get(url, headers=headers) return json.loads(r.text) # print(r.text) numbers = zapros('/v1/direct_numbers/', '') if debug: print(numbers['info']) for res in numbers['info']: description = res['description'] number = res['number'] number_name = res['number_name'] start_date = res['start_date'] stop_date = res['stop_date'] sip = res['sip'] if res['autorenew'] == 'true': autorenew = 0 else: autorenew = 1 monthly_fee = res['monthly_fee'] if res['status'] == 'on': status = 0 else: status = 1 channels = res['channels'] monthly_fee_all = monthly_fee_all + monthly_fee if debug: print('number', number) print('description', description) print('sip',sip) print('number_name', number_name) print('start_date', start_date) print('stop_date', stop_date) print('monthly_fee',monthly_fee) print('status', status) # print('monthly_fee_all',monthly_fee_all) if autorenew != 0: if debug: print('!!!!!!!!!!!!!!!\nautorenew OFF\n!!!!!!!!!!!!!!!\n') if debug: print() sql_insert() balance_info = zapros('/v1/info/balance/','') balance = balance_info['balance'] if debug: print('balance', balance) print('monthly_fee_all',monthly_fee_all) sql = "REPLACE zadarma_balance (id, date, balance, monthly_fee) VALUES (NULL, UTC_TIMESTAMP(), '%s', '%s');" % (balance, monthly_fee_all) try: cursor.execute(sql) db.commit() except: db.rollback() if debug: print('doplata -->', balance - monthly_fee_all ) print('monthly_fee_all', monthly_fee_all) db.close() <spoiler title="  MySQL  "> 

Para desativar a saída de informações no console, é necessário descomentar a linha
debug = false


Para que ambos os scripts funcionem, você provavelmente precisará instalar "solicitações"

 pip install requests 

Tabela para números
 CREATE TABLE IF NOT EXISTS `zadarma_numbers` ( `id` int(10) NOT NULL, `date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `number` varchar(12) DEFAULT NULL, `number_name` varchar(60) DEFAULT NULL, `description` varchar(60) NOT NULL DEFAULT '', `sip` varchar(80) DEFAULT NULL, `start_date` datetime NOT NULL, `stop_date` datetime NOT NULL, `monthly_fee` int(5) DEFAULT NULL, `status` int(1) DEFAULT NULL, `channels` int(3) DEFAULT NULL, `autorenew` int(1) DEFAULT NULL ) ENGINE=InnoDB AUTO_INCREMENT=205 DEFAULT CHARSET=utf8; ALTER TABLE `zadarma_numbers` ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `number` (`number`), ADD KEY `calldate` (`date`), ADD KEY `accountcode` (`monthly_fee`); ALTER TABLE `zadarma_numbers` MODIFY `id` int(10) NOT NULL AUTO_INCREMENT; 


Mesa de equilíbrio
 CREATE TABLE IF NOT EXISTS `zadarma_balance` ( `id` int(10) NOT NULL, `date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `balance` int(10) DEFAULT NULL, `monthly_fee` int(10) DEFAULT NULL ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8; ALTER TABLE `zadarma_balance` ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `balance` (`balance`), ADD KEY `calldate` (`date`); ALTER TABLE `zadarma_balance` MODIFY `id` int(10) NOT NULL AUTO_INCREMENT; 


Repositório com modelo mysql, scripts e dumps.

Source: https://habr.com/ru/post/pt416231/


All Articles