(修正版)SoftRaidの異常とサーバ疎通状態を知らせるLED

更新日 2019-12-27 (金) 15:49:08

以前作成したプログラムはLEDをONOFFするプログラム起動を非同期で起動しないためphpのプログラムが進まないので、Raidが正常になっても一度プログラムを停止しないとLEDのONOFFが停止しない(LEDONOFFプログラム:ledonoffなどの停止とphpプログラム再起動する必要がある)

また、Raid異常のフラグをRaidのサーバから Raspberry Piに送っていたが、RaidのサーバがWAN上にあるときは送れない。Raspberry Piから、Raidのサーバに取りに行くように変更した。

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

サンプルプログラムはRaidサーバの設定を1台にした。また、Raid構成も以下のように1パーティションとした。

''動作内容

// 以下が正常
// --------------------------------------
// | $ cat /proc/mdstat                 |
// | Personalities : [raid1]            |
// |md1 : active raid1 sdb2[1]          |
// |      2369472 blocks [2/1] [_U]     |
// |                                    |
// |md0 : active raid1 sda1[0] sdb1[1]  |
// |       75778496 blocks [2/2] [UU]   |
// --------------------------------------
// カレントフォルダにフラグをセットする
// 正常時(md0のRaidが正常またはビルド中):ootsuji_err_flags = 0
// エラー時(md0のRaidが異常):ootsuji_err_flags = 1

Raidの状態チェックプログラム

30秒ごとにRaidチェックコマンドを実行してその結果、Raidエラーがあればフラグファイルに1を正常時は0を書く。

raidck.php

#! /usr/bin/php

<?php
// NS等のRaid チェック
// 以下が正常
// --------------------------------------
// | $ cat /proc/mdstat                 |
// | Personalities : [raid1]            |
// |md1 : active raid1 sdb2[1]          |
// |      2369472 blocks [2/1] [_U]     |
// |                                    |
// |md0 : active raid1 sda1[0] sdb1[1]  |
// |       75778496 blocks [2/2] [UU]   |
// --------------------------------------
// カレントフォルダにフラグ(_err_flags)をセットする
// 正常時(md0のRaidが正常またはビルド中):_err_flags = 0
// エラー時(md0のRaidが異常):_err_flags = 1 


$count = 0; 

while(1){

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

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

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

    //md0の検索文字
    $search_start_moji = "md0";
    //[UU]とか[U_]などの検索位置
    $search_line = 0;


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

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

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

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

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

   // md0を検索し、その次の行に[UU]とか[U_]などがあるのでその行をスタックする
        if(strpos($output[$i], $search_start_moji) !== false){
            $search_line = $i + 1;
        }
        if($i == $search_line){
            $mojicount = $mojicount + substr_count ($output[$i] , $moji);
        }
   // 「recovery =」は$search_lineの次の行に表示する
        if($i == $search_line + 1){
            $mojicount2 = $mojicount2 + substr_count ($output[$i] , $moji2);
        }

    }

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

    if ($mojicount == 1){ // [UU]が1文字のとき
        $cmd= "echo 0 > " . $flag_path . "_err_flags";

     }else{

        if ($mojicount2 == 1){ //[UU]が0文字でパーティションがリビルド中(「recovery =」の文字列が1つの時
           $cmd= "echo 0 > ". $flag_path . "_err_flags";

        }else{
           $cmd= "echo 1 > " . $flag_path . "_err_flags";

       }
    }

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

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

?>

Raspberry PiでLEDを制御するプログラム

  1. Raidサーバとの疎通が切れるとLEDを点灯する
  2. Raidに障害が発生するとLEDが点滅する

raidck_cl.php

#! /usr/bin/php

<?php
//監視対象サーバがWANにあるため、エラーフラグをサーバからクライアントにGETするプログラム。
 

function read_data($cl, $ping_flag){

//Pingの応答がないときは「1」を返し、サブルーチン終了
         if ($ping_flag == 1)return(1);

// Raid状態フラグファイルの読み込み
        //サーバ IP
        $IP = "192.168.0.170";  //TEST用

        $flag_path ="/home/okada/Raid_ck_script/";
        $flag_file = $flag_path . $cl . "_err_flags";

// クラインとサーバでディレクトリ名が異なるためパス名が変わる
        $flag_path2 =" /home/pi/RadiChack/";


        $cmd = "/usr/bin/rsync -avz -e ssh pi@" . $IP . ":" . $flag_file . $flag_path2;

//      echo $cmd . "\n";
        $ret = exec($cmd);

        $fp = @fopen("/home/pi/RadiChack/" . $cl . "_err_flags", "r");

// ファイルが無いときは「1」を返してサブルーチン終了
        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  $flag 正常 : 0  異常:1

        return $flag;
}




$count = 0;

// GPIOポートを出力に設定

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

while(1){

        $cl = "";
        $d_ip = "192.168.0.170";
//       $d_ip = "192.168.10.200";

        $ping_flag = Ping($d_ip);

        $raid_flag = read_data($cl, $ping_flag);


//Pingが通るとき
       if ( $ping_flag == 0){

//          printf("%d \n", $count % 2);

//LEDONOFFのLinux上のプロセスの文字列を指定

            $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のプロセスが動いているかチェック
            $cmd = "/bin/ps ax | grep /home/pi/RadiChack/ledonoff_20";


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

            if ($raid_flag == 0){
//Raidが正常時LEDONOFFのプロセスの文字列の数が2コ以上多いときは
//LEDONOFFのプロセスが1コ以上動作しているので停止する
                if ($mojicount > 2 ){

                        $cmd = "/usr/bin/killall /home/pi/RadiChack/ledonoff_20";
                        $ret = exec($cmd);
                        $cmd = "/usr/local/bin/gpio -g write 20 0";
                        $ret = exec($cmd);

                }
//Raidエラーの時
            }else{
//Raidが異常時LEDONOFFのプロセスの文字列の数が2コ以上多いときは
//LEDONOFFのプロセスが起動すみなので2重起動にならないように起動しない
//1コのときはLEDONOFFのプロセスが起動していないので起動する

//              echo "文字カウント" . $mojicount . "\n";

                if ($mojicount <= 2 ){
//LED ONOFFプログラムを非同期で実行
                       $cmd = "/home/pi/RadiChack/ledonoff_20 > /dev/null &";
                       $ret = exec($cmd);
                }


            }


       }else{

// Pingでエラーのとき

           $moji = "/home/pi/RadiChack/ledonoff_20";

           $output = array();
           $mojicount = 0;
//LEDONOFFのプロセスが動いているかチェック
           $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;

//Raidの状態に関係なくLEDを点灯させる
//Raidの状態LEDONOFFのプロセスの文字列の数が2以上多いときは
//LEDONOFFのプロセスが動作しているので停止する
//ledonoff_20が起動しているとLEDをONにならないため(点滅するため)
           if ($mojicount > 2 ){
                 $cmd = "/usr/bin/killall /home/pi/RadiChack/ledonoff_20";
                 $ret = exec($cmd);
           }
           $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;
       }
}

?>

LED ONOFF用プログラム

  • 点滅GPIO端子はPIN_SSR(今回はPin20)
  • useconds_t delayを1秒に設定し、点滅周期は: 2秒になる

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

ledonoff_20.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  20

#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
  • 起動
./ledonoff_20

LED ONOFF をRaspberry PiではなくLinuxの画面ダミーで確認用プログラム

ledonoff_20.c

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>


// LED ON/OFF 表示を示すための動作確認用プログラム

#define GPIO_ON  1
#define GPIO_OFF 0
#define PIN_SSR  20

// ledonoff_20の画面出力が標準出力(printf)の時は子プロ終了後に表示する
// そのため子プロ実行中に表示させるため、標準エラー(fprintf(stderr,...)に
// 出力する。


int led_on(int pin_id ) {
    int result;

    fprintf(stderr, "Pin%d の LED ON \n" ,pin_id);
    result = GPIO_ON;
    return result;

}

int led_off(int pin_id ) {
    int result;

    fprintf(stderr, "Pin%d の LED OFF \n" ,pin_id);
    result = GPIO_OFF;
    return result;

}

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


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

  int status_sw;

  // printf("LED ONOFF 開始 \n");
  fprintf(stderr, "LED ONOFF 開始 \n");

  int count = 0;

  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);

    //    count++;

    // if (count > 2) exit(0);


  }

  //  printf("----END-----\n");
}

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-12-27 (金) 15:49:08 (196d)