Предлагаю готовый шаблон для Zabbix и скрипт на Python, для автообнаружения новых номеров провайдера Zadarma(новых, всмысле купленных вами номеров).
В шаблоне есть несколько триггерров и основная информация о номерах. Скрипт работатет с API Zadarma или с базой данных MySQL.
Для работы с MySQL, необходимо заранее по крону или прямо из диалплана с помощью отдельного скрипта положить туда данные.
Оба скрипта под катом.
Теоретически, работа с базой данный может оказаться более актуальной, так как скрипт для складывания туда информации можно запускать после каждого звонка. Таким образом инфо в базе возможно окажется чуточку актуальнее, чем прямая работа с API прям из Zabbix.
В шаблоне Zabbix макрос {$FORCE_API}, форсирует работу скрипта с API Zadarma.
Макрос {$CUT} служит для разделения строки запроса SIP-URI на часть до "@" и после.
У скрипта есть несколько ключей для запуска.
Без ключей или с ключем -l скрипт отдаст список номеров в фрмате json, который подходит для автообнаружения номеров в zabbix.
Ключи "-S, -s, -g, -e, -d, -a" используются только в сочетании с номером
Ключ -m может использоваться как с номером, так и без него
Ключ -b, только без номера
Ключ -c только с ключем -s
Ключ -f форсирует использование API, без него идет запрос в базу данных и его можно использовать с любым ключом.
Второй скрипт:
Для работы обоих скриптов скорее всего понадобится доустановить «requests»
Репозиторий с шаблоном, скриптами и дампами mysql.
В шаблоне есть несколько триггерров и основная информация о номерах. Скрипт работатет с API Zadarma или с базой данных MySQL.
Для работы с MySQL, необходимо заранее по крону или прямо из диалплана с помощью отдельного скрипта положить туда данные.
Оба скрипта под катом.
zadarma_number.py
Скрипт необходимо положить в директорию со скриптами для zabbiz агента, у меня это
Так-же дайте ему права на запуск и на всякий случай измените владельца и группу zabbix:
/etc/zabbix/scripts/
Так-же дайте ему права на запуск и на всякий случай измените владельца и группу 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()
Теоретически, работа с базой данный может оказаться более актуальной, так как скрипт для складывания туда информации можно запускать после каждого звонка. Таким образом инфо в базе возможно окажется чуточку актуальнее, чем прямая работа с API прям из Zabbix.
В шаблоне Zabbix макрос {$FORCE_API}, форсирует работу скрипта с API Zadarma.
Макрос {$CUT} служит для разделения строки запроса SIP-URI на часть до "@" и после.
У скрипта есть несколько ключей для запуска.
Без ключей или с ключем -l скрипт отдаст список номеров в фрмате json, который подходит для автообнаружения номеров в zabbix.
Справка по ключам скрипта:
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 агента.
[-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 "@"
Ключи "-S, -s, -g, -e, -d, -a" используются только в сочетании с номером
Ключ -m может использоваться как с номером, так и без него
Ключ -b, только без номера
Ключ -c только с ключем -s
Ключ -f форсирует использование API, без него идет запрос в базу данных и его можно использовать с любым ключом.
Второй скрипт:
Скрипт API_to_MySql
Так-же дайте ему права на запуск:
Как обозвать скрипт и куда его положить, решайте сами.
Для отключения вывода информации в консоль необходимо раскоментировать строчку
debug = False
chmod +x ./main.py
Как обозвать скрипт и куда его положить, решайте сами.
#! /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 для номеров">
Для отключения вывода информации в консоль необходимо раскоментировать строчку
debug = False
Для работы обоих скриптов скорее всего понадобится доустановить «requests»
pip install requests
Таблица для номеров
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;
Таблица для баланса
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;
Репозиторий с шаблоном, скриптами и дампами mysql.
Magnum_M
«Справка»
Ash666 Автор
Спасибо! Исправил.
Magnum_M
Я конечно извиняюсь, но реализована немного надуманная потребность на мой взгляд.
Смутно представляю, зачем мне в Заббиксе нужны графики баланса, если уведомления о низком балансе со счетом настраиваются в панели управления самого Задарма. И зачем список номеров. Может какой-то редкий паттерн когда очень часто меняются номера?
Но за движуху и оформление до этапа использования плюс. )
Ash666 Автор
Вынужден с Вами согласиться в плане надуманности, хотя с другой стороны удобно, когда мониторинг в одном месте, уведомления теперь в телеграмм сыпятся.
В Заббиксе три триггера, первый срабатывает, когда текущий баланс ниже суммы необходимой для продления всех номеров. Второй, когда на номере отключено авто-продление. Третий, когда статус номера отключен.
Ещё можно сделать триггер на изменение SIP-URI, что теоретически может свидетельствовать о несанкционированном доступе Л.К. Задарма.
Графики я кстати не рисовал.
Есть немного и юмора в этом всем — теперь исправить проблему можно потратив энную сумму денег)