Monitoring Zadarma numbers in Zabbix

I offer a ready-made template for Zabbix and a script in Python, for auto-detection of new numbers of the Zadarma provider (new, in the sense of the numbers you purchased).

The template has several triggerger and basic information about the numbers. The script works with the Zadarma API or with the MySQL database.

To work with MySQL, you need to pre-set the data in advance in crown or directly from the dialplan using a separate script.

Both scripts under the cut.

zadarma_number.py
The script must be put in the directory with scripts for the zabbiz agent, I have it

/etc/zabbix/scripts/ 

Also, give it launch permissions and just in case change the owner and the zabbix group:

 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() 


Theoretically, the work with the database may be more relevant, since the script for folding information there can be run after each call. Thus, the info in the database will probably be a bit more relevant than direct work with the API directly from Zabbix.

In the Zabbix template, the {$ FORCE_API} macro forces the script to work with the Zadarma API.
The macro {$ CUT} is used to divide the string of the SIP-URI request into parts before and after the "@".

The script has several keys to run.

Without keys or with the –l option, the script will give a list of numbers in the json format, which is suitable for autodiscovering numbers in zabbix.

Help for script keys:
usage: Zadarma for Zabbix [-h] [-l] [-n phone number] [-S] [-g] [-e] [-d] [-s]
[-m] [-a] [-b] [-f] [-c [0,1,2] or none]

This program is designed to monitor the numbers of the provider Zadarma and
Originally conceived as a script for a zabbiz agent.

 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 "@" 


The keys "-S, -s, -g, -e, -d, -a" are used only in combination with the number
The -m switch can be used with or without a number.
Key -b, only without a number
The -c key with the -s key only
The -f switch forces the use of the API, without it a query is sent to the database and it can be used with any key.

The second script:

API_to_MySql script
Also give it launch rights:

 chmod +x ./main.py 

How to call the script and where to put it, decide for yourself.

 #! /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  "> 

To disable the display of information in the console, you must uncomment the line
debug = False


For both scripts to work, you will most likely need to install “requests”

 pip install requests 

Table for numbers
 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; 


Table for balance
 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; 


Repository with template, scripts and mysql dumps.

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


All Articles