Так сложилось, что есть необходимость администрирования большого количества (более 50 и будет кратно больше) серверов Trassir (сервера видеонаблюдения) расположенных в разных городах СНГ. В целом оборудование не плохое, но присутствуют проблемы с централизованным управлением в силу особенностей архитектуры системы, каждый сервер (NVR) живет своей жизнью. Некоторые возможности порулить сразу кучей устройств дает «родное» облако, но оно абсолютно неконфигурируемое и использовать его можно лишь как оно есть.
Утро каждого рабочего дня начинается с проверки каждого сервера на работоспособность, что отнимает очень много времени.
У DSSL есть SDK, полное описание доступно тут.
Потратил пару вечеров и написал класс на php, который позволяет веб-серверу проверять состояние Trassir серверов и выводить на страничку. Для доступа к Trassir серверам через web их необходимо сконфигурировать. Во-первых в настройках сервера включить «Разрешить доступ к Trassir из браузера», во — вторых «Trassir SDK» (и задать SDK пароль). Кроме того, рекомендую создать пользователя с усеченными правами для авторизации скрипта (в моем случае пользователь Monitoring, пароль 123, SDK пароль 12345).
В целом SDK дает огромные возможности, ознакомиться можно по ссылке что я давал выше.
Сам код класса:
<?php
class TrassirServer {
/*
1. Создаем новый объект. $serv = new TrassirServer('10.18.242.33', 'Monitoring', '123', '12345');
2. Обязательно проверяем онлайн ли он прежде чем работать с ним дальше! $serv->check_connection();
3. Получение сессии $serv->get_sid();
4. Получение списка объектов как массив $objects = $serv->get_objects(); Необходим пароль SDK
5. Получение здоровья $serv->get_health(); Обязательно перед этим выполнить пункт 3 (get_sid())
*/
public $status = array();
//public $objects = array();
private $ip_address, $name, $sid, $sdk_sid;
private $user;
public function __construct($ip_address, $user, $password, $sdk_password) {
$this->ip_address = $ip_address;
$this->status['ip_address']= $ip_address;
$this->user = $user;
$this->password = $password;
$this->sdk_password = $sdk_password;
}
public function check_connection () {
$url = 'http://'.trim($this->ip_address).':80/';
$curlInit = curl_init($url);
curl_setopt($curlInit,CURLOPT_CONNECTTIMEOUT,2); //время ожидания в секундах
curl_setopt($curlInit,CURLOPT_HEADER,true);
curl_setopt($curlInit,CURLOPT_NOBODY,true);
curl_setopt($curlInit,CURLOPT_RETURNTRANSFER,true);
$response = curl_exec($curlInit);
curl_close($curlInit);
if ($response){
$this->status['online'] = true;
} else {
$this->status['online'] = false;
}
return $this->status['online'];
}
// получить sid
/* {
"success" : "0",
"error_code" : "invalid username or password"
}
/*
Username and Password should match to one of the server users.
*/
public function get_sid(){
if ($this->status['online']){
$url = 'https://' . trim($this->ip_address) . ':8080/login?username=' . $this->user . '&password='.$this->password; //получаем объекты сервера по адресу
$responseJson_str = file_get_contents ($url);
$server_auth = json_decode ($responseJson_str, true); //переводим JSON в массив
if($server_auth['success']==1){
$this->status['sid'] = $server_auth['sid']; //записываем sid массив
}
else{
$this->status['sid'] = false;
}
}
return $this->status['sid'];
}
//получаем объекты сервера
public function get_objects(){
if ($this->status['online']){
$url = 'https://' . trim($this->ip_address) . ':8080/objects/?password='.$this->sdk_password;
$responseJson_str = file_get_contents ($url); //получаем объекты сервера по адресу
$comment_position = strripos ($responseJson_str, '/*'); //отрезаем комментарий в конце ответа сервера
$responseJson_str = substr ($responseJson_str, 0, $comment_position);
//$server_objects = json_decode ($responseJson_str, true); //переводим JSON в массив
$objects = json_decode ($responseJson_str, true);
return $objects;
}
}
//заполнить массив $status
/*
{
"disks": "1",
"database": "1",
"channels_total": "10",
"channels_online": "5",
"uptime": "12902",
"cpu_load": "22.50",
"network": "1",
"automation": "1",
"disks_stat_main_days": "56.15",
"disks_stat_priv_days": "35.03",
"disks_stat_subs_days": "40.20"
}
*/
public function get_health() {
if ($this->status['online'] && $this->status['sid']){
$url = 'https://' . trim($this->ip_address) . ':8080/health?sid='.$this->status['sid'];
$responseJson_str = file_get_contents ($url); //получаем состояние сервера по адресу
$comment_position = strripos ($responseJson_str, '/*'); //отрезаем комментарий в конце ответа сервера
$responseJson_str = substr ($responseJson_str, 0, $comment_position);
$server_health = json_decode ($responseJson_str, true); //переводим JSON в массив
foreach ($server_health as $key => $value){
if (($key == 'disks' || $key == 'database' || $key == 'network' || $key == 'automation')&& $value=='1')
{
echo '<div class = "OK">';
echo $key . ': ';
echo 'OK';
echo '</div>';
}
else if ($key == 'cpu_load' && $value <= 75)
{
echo '<div class = "OK">';
echo 'Загрузка ЦП: ';
echo $value . '%';
echo '</div>';
}
else if ($key == 'uptime' && $value > 3600)
{
echo '<div class = "OK">';
echo 'Аптайм: ';
$day = floor($value/86400);
$value1 = $value - $day*86400;
$hour = floor(($value - $day*86400)/3600);
echo $day.' days '.$hour . ' hours';
echo '</div>';
}
else if ($key == 'uptime' && $value <= 3600)
{
echo '<div class = "error">';
echo $key . ' less than hour : ';
echo $value . ' seconds';
echo '</div>';
}
else if ($key == 'channels_total')
{
echo '<div class = "OK">';
echo 'Каналов всего: ';
echo $value;
$ch_total = $value;
echo '</div>';
}
else if ($key == 'channels_online' && $value == $ch_total)
{
echo '<div class = "OK">';
echo 'Каналов онлайн: ';
echo $value;
$ch_total = $value;
echo '</div>';
}
else if (($key == 'disks_stat_main_days' || $key == 'disks_stat_subs_days')&& $value > 45)
{
echo '<div class = "OK">';
echo $key . ': ';
echo $value;
echo '</div>';
}
else if ( $key == 'disks_stat_priv_days')
{
echo '<div class = "OK">';
echo $key . ': ';
echo $value;
echo '</div>';
}
else
{
echo '<div class = "error">';
echo $key . ': ';
echo $value;
echo '</div>';
}
}
}
}
}
?>
Пример использования подразумевает наличие трех файлов, index.php, view.css (таблица стилей, необязательна, но без нее все будет грустно), list_of_servers.txt (текстовый файл, в котором указаны IP адреса всех серверов для проверки, каждый с новой строки).
view.css:
.error{
background-color: cc3f5b;
#border: 1px dotted red;
#width: 99%;
padding-left: 5px;
}
.trassir_server{
#border-bottom: 1px solid black;
width: 250px;
height: 240px;
background-color: #4682B4;
color: white;
margin-top: 15px;
margin-left: 5px;
display: inline-block;
vertical-align: top;
}
.OK{
background-color: #4169E0;
border-bottom: 1px solid black;
padding-left: 5px;
}
.trassir_server_name{
font-size: 20px;
text-align: center;
height: 30px;
}
body{
background-color: #DCDCDC;
}
index.php
<?php
header('Content-Type: text/html; charset=utf-8');
error_reporting(E_ALL);
require ('classes/TrassirServer.php');
ini_set('max_execution_time', 60);
echo "<link rel='stylesheet' href='./css/view.css'>";
echo '<body>';
$user = 'Monitoring';
$password = '123';
$sdk_password = '12345';
function trassir_server_monitor($ip, $user, $password, $sdk_password){
$serv = new TrassirServer($ip, $user, $password, $sdk_password);
echo '<div class = "trassir_server">';
$serv->check_connection();
if ($serv->status['online']) {
$serv->get_sid();
if ($serv->status['sid']) {
$objects = $serv->get_objects();
if($objects){
foreach ($objects as $obj) //в массиве объектов ищем имя сервера
{
if ($obj['class'] == 'Server')
{
$serv->status['name']= $obj['name'];
}
}
}
echo '<div class = "trassir_server_name">';
echo $serv->status['name'];
echo '</div>';
echo '<div class = "trassir_server_status">';
$serv->get_health();
echo '</div>';
}
}
if (!$serv->status['online'] || !$serv->status['sid'] || !$objects){
echo '<div class = "error">';
echo 'server ' . $ip . '</br>';
echo 'connection error';
echo '</div>';
}
echo '</div>';
}
$list_of_servers = fopen("conf/list_of_servers.txt", "r");
$array = null;
if ($list_of_servers) {
while (($buffer = fgets($list_of_servers)) !== false) {
trassir_server_monitor($buffer, $user, $password, $sdk_password);
}
}
fclose($list_of_servers);
echo '<br/>';
echo '</body>';
?>
Результат в моем случае (на период тестирования всего 4 сервера):
В планах:
- Автоматический регулярный запуск скрипта (пару раз в сутки) и сохранение статистики состояния серверов в БД.
- Возможно централизованное управление УЗ пользователей, если будет актуально к тому моменту когда смогу реализовать первое.
Если есть еще «счастливые» администраторы данной системы, буду рад помощи при желании совместной доработки функционала. Так же если кому-то интересен итоговый результат, но разработкой заниматься не готов — пишите на denis.glushakov@bk.ru, постараюсь про вас не забыть.
Советы по оптимизации кода с радостью приму в комментариях.
Автор: Denissko