Мониторинг серверов Trassir +1

- такой же как Forbes, только лучше.

Так сложилось, что есть необходимость администрирования большого количества (более 50 и будет кратно больше) серверов Trassir (сервера видеонаблюдения) расположенных в разных городах СНГ. В целом оборудование не плохое, но присутствуют проблемы с централизованным управлением в силу особенностей архитектуры системы, каждый сервер (NVR) живет своей жизнью. Некоторые возможности порулить сразу кучей устройств дает «родное» облако, но оно абсолютно неконфигурируемое и использовать его можно лишь как оно есть.

Утро каждого рабочего дня начинается с проверки каждого сервера на работоспособность, что отнимает очень много времени.

У DSSL есть SDK, полное описание доступно тут.

Потратил пару вечеров и написал класс на php, который позволяет веб-серверу проверять состояние Trassir серверов и выводить на страничку. Для доступа к Trassir серверам через web их необходимо сконфигурировать. Во-первых в настройках сервера включить «Разрешить доступ к Trassir из браузера», во — вторых «Trassir SDK» (и задать SDK пароль). Кроме того, рекомендую создать пользователя с усеченными правами для авторизации скрипта (в моем случае пользователь Monitoring, пароль 123, SDK пароль 12345).

image

В целом 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, $user, $sid, $sdk_sid;
	public function __construct($ip_address, $user, $password, $sdk_password) { //конструктор.
		$this->ip_address = $ip_address;
		$this->status['ip_address']= NULL;
		$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'];
	}	
	/*    {
        "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);
				$objects = json_decode ($responseJson_str, true); 			
			return $objects;
		}
		return false;
	}	
	/* пример вовзращаемого массива 
	{
    "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 в массив
		}
	return $server_health;
	}
}
?>

Пример использования подразумевает наличие трех файлов, 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');
	ini_set('max_execution_time', 60);	
	error_reporting(E_ALL);	
	require ('classes/TrassirServer.php');
?>
	<html>
	<head>
		<link rel='stylesheet' href='./css/view.css'>
	</head>
	<body>
<?php
	$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">';
		if ($serv->check_connection()) {
			if ($serv->get_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">';	//вывод здоровья
						$health = $serv->get_health();
						foreach ($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>';
								}	
						}
					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");
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/>';

?>
</body>
</html>

Результат в моем случае (на период тестирования всего 4 сервера):

image

В планах:

  1. Автоматический регулярный запуск скрипта (пару раз в сутки) и сохранение статистики состояния серверов в БД.
  2. Возможно централизованное управление УЗ пользователей, если будет актуально к тому моменту когда смогу реализовать первое.

Если есть еще «счастливые» администраторы данной системы, буду рад помощи при желании совместной доработки функционала. Так же если кому-то интересен итоговый результат, но разработкой заниматься не готов — пишите на denis.glushakov@bk.ru, постараюсь про вас не забыть.

Советы по оптимизации кода с радостью приму в комментариях.

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (5):

  1. ahmpro
    /#10563146

    Почему не пошли по пути интеграции к существующим системам мониторинга? (Zabbix, Prometheus и т.д.)
    Почему параметры доступа и список серверов вшиты в исходник?
    Почему класс TrassirServer что-то выводит?

    • Denissko
      /#10563392

      Ув, ahmpro, я не системный администратор и не профессиональный программист, инструмент делаю для себя в свободное время.
      Отсюда ответы на Ваши вопросы:
      1) С Zabbix и т.д. не знаком. Только что посмотрел на Википедии что это — избыточно для моей задачи. Если есть желание переделать это в плагин (или как это там называется) для Zabbix — действуйте.
      2) 3) PHP изучаю две недели по вечерам, как раз сейчас осваиваю стандарты написания кода. Обязательно это исправлю далее.

      В любом случае спасибо за отзыв. Если тема для Вас актуальна, буду благодарен за профессиональный отзыв.

  2. TimSe
    /#10564592

    Для этой цели у DSSL есть облако: cloud.trassir.com

    • Denissko
      /#10564596

      Если вы знакомы с данным продуктом, то должны знать что получить из облака автоматически долговременную статистику по работоспособности и отказам системы невозможно.
      Если знаете как это сделать — расскажите пожалуйста.
      Кроме того, не всегда из корпоративной сети допустима работа с внешними ресурсами.

  3. Denissko
    /#10564896

    Поправил код, убрал вывод из класса.