SoftRaidの異常とサーバ疎通状態を知らせるLEDを作成

更新日2017-10-15 (日) 06:39:20

SoftRaidの片側が異常になったら、LEDを点滅させる装置をRaspberry Pi で作成した

Raidのサーバ2台を監視する(wwwとmz80)LEDを以前作成したVPN疎通チェックのH/Wに追加する。

   ------------------------              ------------------------
   |Raidサーバ            |              | Raspberry Pi          |
   |(1) 異常監視プログラム|=============>|  (2) LED ONプログラム |
   |HDD異常時に           | エラーフラグ |  エラーフラグ         |
   | エラーフラグ         |ファイル      |  ファイルが1に        |
   | ファイルに           | をrsyncで転送|  になったら           |
   | 1をセット            |              |  (3)点滅プログラム    |
   ------------------------              |  を起動               |
                                         -------------------------
  • 回路図

回路図.png

RaidCK1.jpg

RaidCK2.jpg

(1)異常監視プログラム

  • HDD異常の条件
    • /proc/mdstatのドライブの状態を示す文字列が[UU]でなくなる
    • /proc/mdstatの上記の時ドライブの状態を文字列に「recovery =」がない

以上2つの条件のANDがとれたら異常と判断

異常、正常にかかわらずエラーフラグファイルをrsyncで転送

  • エラーフラグファイルの内容
    • 正常時:0
    • 異常時:1
  • チェックインターバルは30秒間隔

「www_err_flags」のコメントを外し、「mz80_err_flags」をコメントするとwww用になる。

このプログラムは各Raidサーバに配置する。

mz80_raidck.php

#! /usr/bin/php

<?php

$count = 0;

while(1){

    $output = array();
    $output2 = array();

    $raid_flag = 0;
    $IP = "192.168.10.123";
    $flag_path = "/home/okada/Raid_ck_script/";

    $mojicount = 0; //「[UU]」の文字列カウント
    $mojicount2 = 0; //「recovery =」の文字列カウント
    $moji = "[UU]";
    $moji2 = "recovery =";

   // [UU]の文字があったらカウントする。合計が3つが正常
   // [UU]は正常 recovery =はリビルド中

   $cmd = "/bin/cat /proc/mdstat";

   $ret = exec($cmd ,$output);

   for ($i = 0 ; $i < count($output); $i++) {

   //    echo $i . $output[$i] . "\n";

        $mojicount = $mojicount + substr_count ($output[$i] , $moji);
        $mojicount2 = $mojicount2 + substr_count ($output[$i] , $moji2);


   }

//     echo $mojicount . " : " .$mojicount2 . "\n";

    if ($mojicount == 2){
        $cmd= "echo 0 > " . $flag_path . "mz80_err_flags";
//      $cmd= "echo 0 > www_err_flags";
    }else{
        if ($mojicount2 == 1){ //パーティション1つがリビルド中
           $cmd= "echo 0 > ". $flag_path . "mz80_err_flags";
//           $cmd= "echo 0 > www_err_flags";
        }else{
           $cmd= "echo 1 > " . $flag_path . "mz80_err_flags";
//         $cmd= "echo 1 > www_err_flags";
       }
    }

    $ret = exec($cmd);
//    echo $cmd;

    // IPとの通信確認 通信できないときは rsyncを行わない
    $cmd = "/bin/ping -w 10 -c 2 ".$IP;

    $ret = exec($cmd ,$output2);

    $mojicount3 = 0;
    $moji3 = ", 0% packet loss";

    //通信可能な時はpingを2回飛ばし 0%のロスで判断
    //文字列 $moji3が結果に1回存在する

    for ($i = 0 ; $i < count($output2); $i++) {

        $mojicount3 = $mojicount3 + substr_count ($output2[$i] , $moji3);

    }

    if ( $mojicount3 == 1){

       $cmd = "rsync -avz -e ssh " . $flag_path . "mz80_err_flags pi@" . $IP .":~pi/RadiChack/";
//       $cmd = "rsync -avz -e ssh /home/okada/test/www_err_flags pi@" . $IP .":~pi/RadiChack/";

       $ret = exec($cmd);
    }

    $count++;
//    echo "回数 ". $count . " \n";
    sleep(30);
} 

?>

起動設定

  • /etc/rc.d/rc.local
su - okada -c /home/okada/Raid_ck_script/mz80_raidck.php &

(2)LED ON プログラム

エラーフラグファイルの内容が「1」になったら(3)のLED点滅プログラムを起動。 エラーフラグファイルの内容が「0」になったら(3)のLED点滅プログラムを停止し、LEDを消灯する。

サーバとの疎通がなくなったらLEDを点灯する。

このプログラムは Raspberry Pi に配置

raidck_sv.php

#! /usr/bin/php

<?php

function read_data($cl){

// フラグファイルの読み込み
        $fp = @fopen("/home/pi/RadiChack/" . $cl . "_err_flags", "r");

        if (!$fp) return(1);
        $flag = "";

        while(!feof($fp)){
                $s = fgets($fp, 4096);
                $flag = $flag . $s;

        }

        fclose($fp);
        // echo "FLAG= ". $flag;

        return $flag;
}

function Ping($ip){

        $cmd = "/bin/ping -c 1 " . $ip ;

        $s_moji = "1 received, 0% packet loss";
        $ret = exec($cmd ,$output);
        $mojicount = 0;
        for ($i = 0 ; $i < count($output); $i++) {
                $mojicount = $mojicount + substr_count ($output[$i] , $s_moji);
//              echo $output[$i]. "\n";
        }
        if ($mojicount == 1){
                $flag =  0;
        }else{
                $flag =  1;
        }
// Ping正常 : 0  異常:1
        return $flag;
}


$count = 0;

// GPIOポートを出力に設定
$cmd = "/usr/local/bin/gpio -g mode 16 out";
$ret = exec($cmd);

$cmd = "/usr/local/bin/gpio -g mode 20 out";
$ret = exec($cmd);

//$cl = "mz80";

//$d_ip = "192.168.10.46";

while(1){

// ループを一回ルごとにクライアントをmz80とwwwを切り替え
        if (($count % 2) == 0){
              $cl = "www";
              $d_ip = "192.168.10.46";
        }else{
              $cl = "mz80";
              $d_ip = "182.236.42.21";
        }
//Pingが通るときLED OFF
       if ( Ping($d_ip) == 0){

//          printf("%d \n", $count % 2);
            $flag = read_data($cl);

//LEDONOFFのプロセスの文字列を指定
            if (strcmp($cl ,"mz80") == 0){
                $moji = "/home/pi/RadiChack/ledonoff_16";
                $cmd = "/usr/local/bin/gpio -g write 16 0";
            }else{
                $moji = "/home/pi/RadiChack/ledonoff_20";
                $cmd = "/usr/local/bin/gpio -g write 20 0";
            }
//PingのエラーでLEDがONの状態から,Ping正常で戻ったときLEDをOFFにするため
            $ret = exec($cmd);


            $output = array();
            $mojicount = 0;
//LEDONOFFのプロセスが動いているかチェック
            if (strcmp($cl ,"mz80") == 0){
                $cmd = "/bin/ps ax | grep /home/pi/RadiChack/ledonoff_16";
            }else{
                $cmd = "/bin/ps ax | grep /home/pi/RadiChack/ledonoff_20";
            }

//LEDONOFFのプロセスの文字列の数をカウント
            $ret = exec($cmd ,$output);
            for ($i = 0 ; $i < count($output); $i++) {
                $mojicount = $mojicount + substr_count ($output[$i] , $moji);
//              echo $output[$i]. "\n";
            }
//          echo $mojicount;

            if ($flag == 0){
//Raidが正常時LEDONOFFのプロセスの文字列の数が2より多いときは
//LEDONOFFのプロセスが動作しているので停止する
                if ($mojicount > 2 ){
                        if (strcmp($cl ,"mz80") == 0){
                              $cmd = "/usr/bin/killall /home/pi/RadiChack/ledonoff_16";
                              $ret = exec($cmd);
                              $cmd = "/usr/local/bin/gpio -g write 16 0";
                              $ret = exec($cmd);
                        }else{
                              $cmd = "/usr/bin/killall /home/pi/RadiChack/ledonoff_20";
                              $ret = exec($cmd);
                              $cmd = "/usr/local/bin/gpio -g write 20 0";
                              $ret = exec($cmd);
                        }
                }

            }else if($flag == 1){
//Raidが異常時LEDONOFFのプロセスの文字列の数が3より多いときは
//LEDONOFFのプロセスが起動すみなので2重起動にならないように起動しい
//3未満のときはLEDONOFFのプロセスが起動していないので起動する

                if ($mojicount < 3 ){
                        if (strcmp($cl ,"mz80") == 0){
                              $cmd = "/home/pi/RadiChack/ledonoff_16 > /dev/null &";
                        }else{
                              $cmd = "/home/pi/RadiChack/ledonoff_20 > /dev/null &";
                        }
                        $ret = exec($cmd);
                }
            }


       }else{

// Pingでエラーのとき

           if (strcmp($cl ,"mz80") == 0){
                $moji = "/home/pi/RadiChack/ledonoff_16";
           }else{
                $moji = "/home/pi/RadiChack/ledonoff_20";
           }
           $output = array();
           $mojicount = 0;
//LEDONOFFのプロセスが動いているかチェック
           if (strcmp($cl ,"mz80") == 0){
                $cmd = "/bin/ps ax | grep /home/pi/RadiChack/ledonoff_16";
           }else{
                $cmd = "/bin/ps ax | grep /home/pi/RadiChack/ledonoff_20";
           }

//LEDONOFFのプロセスの文字列の数をカウント
           $ret = exec($cmd ,$output);
           for ($i = 0 ; $i < count($output); $i++) {
                $mojicount = $mojicount + substr_count ($output[$i] , $moji);
//              echo $output[$i]. "\n";
           }
//         echo $mojicount;

           if ($flag == 0){
//Raidが正常時LEDONOFFのプロセスの文字列の数が2より多いときは
//LEDONOFFのプロセスが動作しているので停止する
                if ($mojicount > 2 ){
                        if (strcmp($cl ,"mz80") == 0){
                              $cmd = "/usr/bin/killall /home/pi/RadiChack/ledonoff_16";
                              $ret = exec($cmd);
                              $cmd = "/usr/local/bin/gpio -g write 16 1";
                              $ret = exec($cmd);
                        }else{
                              $cmd = "/usr/bin/killall /home/pi/RadiChack/ledonoff_20";
                              $ret = exec($cmd);
                              $cmd = "/usr/local/bin/gpio -g write 20 1";
                              $ret = exec($cmd);
                        }
                }else{
                        if (strcmp($cl ,"mz80") == 0){
                              $cmd = "/usr/local/bin/gpio -g write 16 1";
                        }else{
                              $cmd = "/usr/local/bin/gpio -g write 20 1";
                        }
                        $ret = exec($cmd);
                }
           }

       }
       $count++;

       echo $cl . "\n";
       echo "回数 ". $count ." \n";
       sleep(10);
       if ($count > 999){
           $count = 0;
       }

}

?>

(3)LED 点滅 プログラム

  • 点滅GPIO端子はPIN_SSR
  • 点滅周期はuseconds_t delayX2: 2秒に設定

このプログラムはRaspberry Piに配置する。

ledonoff.c

#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <stdlib.h>    // atof(charからdoubleに変換時必要
#include <stdbool.h>
#include <time.h>
#include <unistd.h>

// * ============ SSR Setting=========
//#define PIN_SSR  12 

#define GPIO_ON  1
#define GPIO_OFF 0

int led_on(int pin_id ) {
    int result;

    digitalWrite( pin_id, GPIO_ON );
    result = GPIO_ON;
    return result;

}

int led_off(int pin_id ) {
    int result;

    digitalWrite( pin_id, GPIO_OFF );
    result = GPIO_OFF;
    return result;

}

int main ( int argc, char **argv ) {

  /* Initialize wiringPi */
  if( wiringPiSetupGpio() == -1 ) return 1;

  /* Initialize GPIO */
  pinMode( PIN_SSR, OUTPUT );

// マイクロ秒 (1秒)
useconds_t delay=1000000;

int status_sw;

while (1){

  status_sw = led_on(PIN_SSR);

  usleep(delay);

//  printf("ON %d %d\n" ,status_sw, PIN_SSR);
  status_sw = led_off(PIN_SSR);

  usleep(delay);

//  printf("OFF %d\n" ,status_sw);

}

}
  • コンパイル
gcc -o ledonoff ledonoff.c -lwiringPi
  • 起動

GPIO16ポートの時(パラメータにGPIOポート番号を指定)

./ledonoff 16

添付ファイル: file回路図.png 26件 [詳細] fileRaidCK2.jpg 26件 [詳細] fileRaidCK1.jpg 21件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-10-15 (日) 06:39:20 (133d)