Простой монитор работоспособности PHP для серверов Windows и коммутаторов Cisco - PullRequest
3 голосов
/ 27 мая 2011

Я написал (хорошо собранный из кода других людей) очень простой монитор работоспособности для наших серверов - это всего лишь монитор ICMP (ping), и он очень хорошо работает для нашего ограниченного количества серверов (около 20),и очень быстроВот код (реальные функции проверки пинга, я думаю, основаны на работе Бирка Дженсена (http://birk -jensen.dk / 2010/09 / php-ping / ), и я только что использовал его функцииотображать зеленый кружок PNG, когда все в порядке, и красные для каждого сервера, который не работает (если есть).

<html>
<head>
<style type='text/css'>

*{
    font-family:verdana,tahoma,arial;
    font-size:17px;
}

.light{width:30px;}

h1{
        font-size:25px;
}
</style>



<meta http-equiv="refresh" content="30">
</head>
<body>
<?php

$time1=date('H:i:s');
echo "Last Refresh Time = $time1<br/><hr/>";

error_reporting(0);

/*-----------------------------------------------------------------------------------------*/    
    // Checksum calculation function
    function icmpChecksum($data)
    {
    if (strlen($data)%2)
    $data .= "\x00";

    $bit = unpack('n*', $data);
    $sum = array_sum($bit);

    while ($sum >> 16)
    $sum = ($sum >> 16) + ($sum & 0xffff);

    return pack('n*', ~$sum);
    }


/*-----------------------------------------------------------------------------------------*/
    function PingTry1($pingaddress){
    // Making the package
    $type= "\x08";
    $code= "\x00";
    $checksum= "\x00\x00";
    $identifier = "\x00\x00";
    $seqNumber = "\x00\x00";
    $data= "testing123";
    $package = $type.$code.$checksum.$identifier.$seqNumber.$data;
    $checksum = icmpChecksum($package); // Calculate the checksum
    $package = $type.$code.$checksum.$identifier.$seqNumber.$data;
    // And off to the sockets
    $socket = socket_create(AF_INET, SOCK_RAW, 1);

    socket_set_option ( $socket, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>1, "usec"=>0) );
    socket_connect($socket, $pingaddress, null);

    $startTime = microtime(true);
    socket_send($socket, $package, strLen($package), 0);
    if (socket_read($socket, 255)) {
    return true;
    }
    else{
    return false;
    }

    socket_close($socket);

    }
/*-----------------------------------------------------------------------------------------*/
   function DoTheCheck($name,$ip){
       global $errors;
       global $j;
       if (PingTry1($ip)==1){
    //do nothing
                      }else{
                      $j++;
                      $errors[$j] = "$name --> $ip";

                      }

    }
/*-----------------------------------------------------------------------------------------*/

//READ IN THE INI FILE INTO $filedata Array

$myFile1="hosts.ini";
$filehandle1 = fopen($myFile1, 'r') or die("Couldn't open file [$myFile1]");
$number1=count(file($myFile1));;
$filedata = fread($filehandle1, filesize($myFile1));
fclose($filehandle1);

// Create an array with each line of the file
$array1 = explode("\r\n", $filedata);

unset($filedata); //free up a bit of memory

foreach ($array1 as &$line) { // step through the array, line by line
    if (!empty($line)){
list ($name,$ip)=split(",",$line);
    DoTheCheck($name,$ip);
                 }
}


    if ($errors){

            echo 'The Following Hosts are down - <br/><br/><table>';

foreach ($errors as &$value) {
    $k++;
    echo '<tr><td><img class="light" src="red.png" /></td><td>'.$errors[$k].'</td></tr>';
}
echo '</tr></table>';
    }
else{echo '<img class="light" src="green.png" /><h1>ALL IPS ARE UP!</h1>';}




    ?>
    </body>
    </html>

Приведенный выше код отлично работает для серверов, но, похоже, не работает вообще дляКоммутаторы Cisco - вероятно, что-то связанное с тем, как они «пингуют» как таковые.

Я давно не работал над этим сценарием из-за обязательств колледжа и т. Д., Но я вернулся к выполнениюстолько исследований Google, сколько я могу, но, по общему признанию, я в лучшем случае PHP n00b уровня 2 или 3. Сегодня я нашел пару решений, которые работают для коммутаторов, но у них есть периоды ожидания 5 или 6 секунд, что недопустимо, поскольку яхочу, чтобы система зациклилась как можно больше и как можно более чисто, и записала время простоя для последующего построения графика.

Например - я пробовал это:

   function ping($host, $timeout = 1) {
                /* ICMP ping packet with a pre-calculated checksum */
                $package = "\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost";
                $socket  = socket_create(AF_INET, SOCK_RAW, 1);
                socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
                socket_connect($socket, $host, null);

                $ts = microtime(true);
                socket_send($socket, $package, strLen($package), 0);
                if (socket_read($socket, 255))
                        $result = microtime(true) - $ts;
                else    $result = false;
                socket_close($socket);

                return $result;
        }

, а также это:

    $url         = '192.168.1.1'; 
    $socket       = ( bool )false; 
    $error      = ( bool )false; 

    $socket = @fsockopen( $url, 23, $errno, $errstr, 1 ) or $error = ( bool )true; 

    if ( ( $socket ) && ( !$error ) ) 
    { 
        echo "bound";
        /* socket is bound - do something */ 
    } 
    else 
    { 
        echo "not bound , [$errstr]";
        /* socket is dead - errors are in $errno & $errstr */ 
    }  

if ($socket)fclose($socket);

И они оба, кажется, работают, когда хост находится в сети, но если я дам ему IP, который не существует (для тестирования, как если бы хост был в автономном режиме), потребуется около 5 или более секунд для тайм-аутаодин IP, который слишком медленный для моих нужд.

Можно ли сделать это, используя pcntl_fork или даже curl с многопоточностью?или несколько вызовов 'exec' или даже AJAX (я готов попробовать что-нибудь на этом этапе)

или какой-то код уровня данных (уровень 2). Сканирование на Mac также было бы неплохо - я не ожидаюлюбой, кто напишет полный код, но я уверен, что кто-то, кто делал подобные вещи раньше, мог бы иметь представление о подводных камнях и о том, как их обойти.

Итак, в целом - просто и легкоИсправление было бы неплохо (я буду продолжать мечтать :-D), но любая помощь или совет очень ценятся.

РЕДАКТИРОВАТЬ - после некоторого совета попробовать Net_Ping в PEAR, я получил следующий код:

<?php

$time1=date('H:i:s');
echo "Last Refresh Time = $time1<br/><hr/>";

//not sure if still needed -       error_reporting(0);


require_once "Net/Ping.php";
$ping = Net_Ping::factory();

$ping->setArgs(array('count' => 2, 'ttl' => 50, 'timeout' => 1));
/*---------------------------------------------------------------------*/
function DoPing($ip)
{
    global $ping;

    $results = $ping->ping($ip);
    if ($results->_loss==0) {return true;}else{return false;}
}
/*---------------------------------------------------------------------------------*/
   function DoTheCheck($name,$ip){
       global $errors;
       global $j;

       if (DoPing($ip)==1){
    //do nothing
                      }else{
                      $j++;
                      $errors[$j] = "$name --> $ip";
                      }
    }
/*-----------------------------------------------------------------------------------*/

//READ IN THE INI FILE INTO $filedata Array

$myFile1="hosts.ini";
$filehandle1 = fopen($myFile1, 'r') or die("Couldn't open file [$myFile1]");
$number1=count(file($myFile1));;
$filedata = fread($filehandle1, filesize($myFile1));
fclose($filehandle1);

// Create an array with each line of the file
$array1 = explode("\r\n", $filedata);

unset($filedata); //free up a bit of memory

foreach ($array1 as &$line) { // step through the array, line by line
    if (  (!empty($line)) && (!strstr($line,'##'))  ) {
list ($name,$ip)=split(",",$line);
    DoTheCheck($name,$ip);
                 }
}

    if ($errors){

            echo 'The Following Hosts are down - <br/><br/><table>';

foreach ($errors as &$value) {
    $k++;
    echo '<tr><td><img class="light" src="red.png" /></td><td>'.$errors[$k].'</td></tr>';
}
echo '</tr></table>';
    }
else{echo '<img class="light" src="green.png" /><h1>ALL IPS ARE UP!</h1>';}

?>

но это слишком медленно ... требуется около минуты или двух, чтобы проверить около 20 серверов и 10 коммутаторов.Мне нужно добавить около 100 переключателей, так что будет только медленнее.Должен быть лучший способ сделать это.Опять же, любая помощь всегда очень ценится.Я, наверное, попробую Munin, но реально мне нужно что-то, что я могу интегрировать в интранет моей компании (PHP).

1 Ответ

1 голос
/ 01 июня 2011

Вы уже пробовали правильную систему мониторинга, такую ​​как Munin ? это работает, в отличие от вашего сценария ручной работы. Я использую его для контроля моего интернет-соединения и наличия серверов; это обеспечивает пинг плагин для этого. Мунин также отправляет письма в случае ошибок и рисует красивые графики.

Есть также Nagios и Cacti, но я нашел Munin наиболее простым в настройке.

Если вы действительно действительно хотите продолжать использовать только PHP, взгляните на пакет PEAR Net_Ping , который предоставляет API для отправки пингов.

Редактировать: Скорость

Поскольку пинг всех хостов один за другим слишком медленный, вам нужно распараллеливать ваши пинги. Net_Ping не поддерживает это, поэтому вы должны запускать несколько процессов PHP параллельно. Используйте либо PHP-функции pcntl, либо одну из shell_exec функций. Скрипт ping просто передал бы ping хосту в качестве единственного параметра командной строки, и он записывает результат ping в общий файл журнала. Основной сценарий ожидает завершения всех сценариев проверки связи и собирает зарегистрированную информацию.

...