Monitoring Zadarma numbers in Zabbix

  • Tutorial
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 a MySQL database.

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

Both scripts under the cut.

zadarma_number.py
Скрипт необходимо положить в директорию со скриптами для zabbiz агента, у меня это

/etc/zabbix/scripts/

Так-же дайте ему права на запуск и на всякий случай измените владельца и группу zabbix:


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

#! /usr/bin/env python3import 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 = 0defsql_result(sql):
    cursor.execute(sql)
    data = cursor.fetchall()
    return data
defstr_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)defcreateParser():
    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
defapi_zapros(method,data):ifnot 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)
defno_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]
defzapros(*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:])
ifnot 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))
ifnot namespace.force_API:
    db.close()


Theoretically, the work with the database can 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]

Это программа предназначена для мониторинга номеров провайдера Zadarma и
изначально задумывалась как скрипт для 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 "@"


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

The second script:

API_to_MySql script
Так-же дайте ему права на запуск:


chmod +x ./main.py

Как обозвать скрипт и куда его положить, решайте сами.

#! /usr/bin/env python3from 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()
defsql_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()
defzapros(method,data):ifnot 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 = 0else:
        autorenew = 1
    monthly_fee = res['monthly_fee']
    if res['status'] == 'on':
        status = 0else:
        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 для номеров">

Для отключения вывода информации в консоль необходимо раскоментировать строчку
debug = False


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

pip install requests

Table for numbers
CREATETABLEIFNOTEXISTS`zadarma_numbers` (
  `id`int(10) NOTNULL,
  `date` datetime NOTNULLDEFAULT'0000-00-00 00:00:00',
  `number`varchar(12) DEFAULTNULL,
  `number_name`varchar(60) DEFAULTNULL,
  `description`varchar(60) NOTNULLDEFAULT'',
  `sip`varchar(80) DEFAULTNULL,
  `start_date` datetime NOTNULL,
  `stop_date` datetime NOTNULL,
  `monthly_fee`int(5) DEFAULTNULL,
  `status`int(1) DEFAULTNULL,
  `channels`int(3) DEFAULTNULL,
  `autorenew`int(1) DEFAULTNULL
) ENGINE=InnoDB AUTO_INCREMENT=205DEFAULTCHARSET=utf8;
ALTERTABLE`zadarma_numbers`ADD PRIMARY KEY (`id`),
  ADDUNIQUEKEY`number` (`number`),
  ADDKEY`calldate` (`date`),
  ADDKEY`accountcode` (`monthly_fee`);
ALTERTABLE`zadarma_numbers`MODIFY`id`int(10) NOTNULL AUTO_INCREMENT;


Table for balance
CREATETABLEIFNOTEXISTS`zadarma_balance` (
  `id`int(10) NOTNULL,
  `date` datetime NOTNULLDEFAULT'0000-00-00 00:00:00',
  `balance`int(10) DEFAULTNULL,
  `monthly_fee`int(10) DEFAULTNULL
) ENGINE=InnoDB AUTO_INCREMENT=24DEFAULTCHARSET=utf8;
ALTERTABLE`zadarma_balance`ADD PRIMARY KEY (`id`),
  ADDUNIQUEKEY`balance` (`balance`),
  ADDKEY`calldate` (`date`);
ALTERTABLE`zadarma_balance`MODIFY`id`int(10) NOTNULL AUTO_INCREMENT;


Repository with a template, scripts and mysql dumps.

Also popular now: