リアルタイムで計算状況を表示するシステムの構築!【電子実験ノートを自作してみた!導入コストゼロ!】(2/5)

本記事は、前回の記事(電子実験ノートを自作してみた!導入コストゼロ!(1/5))の続きになります。

今回は、リアルタイムで複数の計算機での job の実行状況を表示させるシステムの構築を行います。

初心者の方でも、PHPMySQLGoogle Chart Tools を使用して簡単に書くことが出来ます。

参考電子実験ノートを自作してみた!導入コストゼロ!(1/5)
参考CRUD を実装!電子実験ノートを自作してみた!導入コストゼロ!(3/5)
参考PHP でブラウザから job を投入する。電子実験ノートを自作してみた!導入コストゼロ!(4/5)
参考ログイン機能を実装する。電子実験ノートを自作してみた!導入コストゼロ!(5/5)

目的

管理人は、いろいろな場所に設置された複数の計算機を使用して計算を進めています。

一つの計算機しか使用していない場合は、job の実行状況の把握が簡単ですが、複数となってくると、少し時間が取られます。

それぞれの計算機にジョブ・スケジューラーがインストールされていはいるものの、いちいち terminal を起動して、各計算機にログインして計算状況を確認する必要があり、毎日結構な時間を取られていました。。。

そこで、今回は計算状況をリアルタイムで確認するシステムの構築を目的とします。

システム構成

  1. 現在実行中の job の id, job名, 計算状況, 計算機名, job 番号, 計算の種類, ディレクトリ, 作成日時などをデータベース(MySQL)に登録します。
  2. PHP で自動的に各計算機にログインし、計算状況を確認し、データベースをアップデートする。
  3. Google Chart Tools を使い、ウェブブラウザ上で形式を整えて出力する。

という構成になります。

環境構築

それでは、まずは環境設定から初めていきましょう!この記事では、mac での構築方法を解説します。windows の人は自分で環境構築を行ってください。

レンタルサーバーをお使いの方は、おそらくもう環境構築はほとんど終わっていますので、php の libssh2 のみ追加すれば良いと思います。

1.こちらのページから MAMP を入手し、インストールしてください。

2.次に、PHP で ssh 接続を使えるようにするために、以下の手順で libssh2 をインストールしてください。php のバージョンは適宜変更してください。

wget https://pecl.php.net/get/ssh2-1.1.2.tgz
tar zxvf ssh2-1.1.2.tgz
cd ssh2-1.1.2
/Applications/MAMP/bin/php/php7.4.2/bin/phpize 
./configure --with-php-config=/Applications/MAMP/bin/php/php7.4.2/bin/php-config
make 
sudo make install

最後に、/Applications/MAMP/bin/php/php7.4.2/conf にある php.ini を編集します。

php.ini を開き、ファイルの一番下に
extension = ssh2.so
と書き加えてください。

これで、php で ssh 接続を使えるようになります。

仮想サーバーの起動

続いて、Application フォルダにある MAMP を起動してください。

ブラウザに初期ページが表示され、アドレスバーには “http://localhost:8888/MAMP” と書かれているはずです。

次に、/Applications/MAMP/htdocs のフォルダを開いき、新規作成で notebook というフォルダを作成してください。

これから書く php, css, javascript や画像ファイルは、全てこのフォルダに入れていきます。

まずは、下のリンクから html ファイルと css ファイルを ダウンロードし、/Applications/MAMP/htdocs/notebook に入れ、ウェブブラウザで http://localhost:8888/MAMP/notebook/index.html にアクセスしてみて下さい。

下画像のページが表示されるはずです。

ここまで出来たら、環境構築は終了です。

(注)タブメニューの内容やロゴ、ユーザー名の表示などは、別ファイルにして読み込ませた方がコードが簡潔で見やすくなるのですが、今回の配布ファイルでは都合上ベタうちにしてあります。

MySQL の設定

次に、アドレスバーに、http://localhost:8888/phpmyadmin と入力してください。MySQL のページに行くことができます。

note というデータベースを作成し、その中に report というテーブルを作成して下さい(下図参照)。

report 内には、id, title, content, status, machine, job_number, directory, calculation, created_at, modified_at という 10 個の項目を作成して下さい。

id は int 型で、 Auto increment を設定して下さい。その他の項目は、上図を参考に作成して下さい。

この MySQL に全てのノート情報や計算情報が書き込まれます。

次に下のリンクから report.sql というファイルをダウンロードして下さい。

上図 phpMyAdminの画面のインポートというところからファイルをアップロードを選択すれば、簡単にインポートできます。

Google Chart Tools

Google Chart Tools を使うと簡単に表が作れてしまいます。

下に示すように、data.addColumn で項目を追加していき、data.addRows にデータを入れていきます。

var data = new google.visualization.DataTable();
       data.addColumn('string', 'No.');
       data.addColumn('string', 'jobタイトル');
       data.addColumn('string', '計算状況');
       data.addColumn('string', '計算機名');
       data.addColumn('string', 'job番号');
       data.addColumn('string', '計算の種類');
       data.addColumn('string', 'ディレクトリ');
       data.addColumn('string', '作成日時');
       data.addRows([
[1, test_tsopt.com, END, machine1, 001, tsopt, home/user, 2020/07/07],
[2, test_tsopt.com, RUN, machine1, 002, tsopt, home/user, 2020/07/07],
[3, test_tsopt.com, QUE, machine1, 003, tsopt, home/user, 2020/07/07],
])

では、以下のリンクからファイルをダウンロードして、notebook フォルダに置いてください。

ブラウザで http://localhost:8888/MAMP/notebook/calculation_status.php を開いてみて下さい。

以下のような画面が表示されると思います。

これは、単に MySQL の内容を表示しているだけになります。

ここで、data.addRows の部分を php を使って、MySQL の情報を書き込むようにします。

上でダウンロードしたファイルでは、status_check 部分が全てコメントアウトされていますが、それを外すと下のようになります。

var data = new google.visualization.DataTable();
       data.addColumn('string', 'No.');
       data.addColumn('string', 'jobタイトル');
       data.addColumn('string', '計算状況');
       data.addColumn('string', '計算機名');
       data.addColumn('string', 'job番号');
       data.addColumn('string', '計算の種類');
       data.addColumn('string', 'ディレクトリ');
       data.addColumn('string', '作成日時');
       data.addRows([
            <?php foreach($notes as $note): ?>
                [
                    "<a href='report.php?id=<?php echo $note['id']; ?>'><?php echo sprintf('%03d', (int)$note['id']); ?></a>",
                    "<a href='report.php?id=<?php echo $note['id']; ?>'><?php 
                        echo $note['title'];
                    ?></a>",
                    "<?php
                        $filename = current(explode('.', $note['title'])) . ".log";

                        if($note['machine'] == '7960x'){
                            $status = status_check($note['status'], $note['directory'], $connection_7960x, $filename, $note['job_number']);
                        }elseif($note['ripper'] == 'ripper'){
                            $status = status_check($note['status'], $note['directory'], $connection_ripper, $filename, $note['job_number']);
                        }elseif($note['3900x'] == '3900x'){
                            $status = status_check($note['status'], $note['directory'], $connection_3990x, $filename, $note['job_number']);
                        }
                       
                        echo $status;
                        
                        if($note['status'] !== $status){
                            $query = $pdo->prepare('INSERT INTO report(title, content, created_at) VALUES (?, ?, ?)');
                            $query = $pdo->prepare('UPDATE report SET status=? WHERE id=?;');
                            $query->bindValue(1,$status);
                            $query->bindValue(2,$note['id']);
                            $query->execute();
                        }
                    ?>",
                    "<?php echo $note['machine']; ?>",
                    "<?php echo $note['job_number']; ?>",
                    "<?php echo $note['calculation']; ?>",
                    "<?php echo $note['directory']; ?>",
                    "<?php echo $note['created_at']; ?>"
                ],
            <?php endforeach; ?>
        ]);

上記のコードでは、status_check という自前の関数を使って、計算機にログインして各 job を進捗状況をチェックするようになっています。

そして、MySQL 内の計算状況と status_check で確認した状況が異なっている場合には、自動的に MySQL の内容をアップデートするようになっています。

次に、 status_check の中身を説明いたします。

PHP を用いた ssh 接続

前述した libssh2 を用いることにより PHP を介して各計算機にリモートログインし、計算状況を確認することが出来ます。

そのためには、ssh2_connectssh2_exec という libssh2 に含まれている二つの関数を用いて、connect_machine, connect_exec, status_check という自前の関数を 3 つ作る必要があります。

まずは、下記のように ssh2_connect という関数を使ってリモートログインします。

function connect_machine($machine_name){
            $IP = array('7960x'=>'10.174.xxx.xxx', 'ripper'=>'10.174.xxx.xxx', '3900x'=>'10.174.xxx.xxx');
            $user = array('7960x'=>'intel7960x', 'ripper'=>'ripper', '3900x'=>'ryzen3900x');
            $pass = array('7960x'=>'password1', 'ripper'=>'password2', '3900x'=>'password3');
            $connection = ssh2_connect($IP[$machine_name], 22);
            if(!ssh2_auth_password($connection, $user[$machine_name], $pass[$machine_name])) die('VPN 接続状況を確認してください。');
            return $connection;
        }

ssh 接続には、IPアドレス、ユーザー名、パスワード、ポート番号の4つの情報が必要です。

今回は、7960x, ripper, 3900x という 3 つの計算機を例にしています。連想配列を用いると楽です。また、上記の例では、ポート番号は全計算機 22 となっています。

ssh2_connect 関数は、返り値としてリソースを返します。(接続失敗の時は falseを返す)。これを $connection という変数に格納します。

続いて、connect_exec 関数について説明します。

connect_exec 関数は、「リソース」と「計算機上で実行したいコマンド」の二つを引数としてとり、コマンドの実行結果を返してくれます。

下に示すように、connect_exec 関数では、 ssh2_exec の結果をリスト形式で返すようにしています。

function connect_exec($connection, $command){
            $stream = ssh2_exec($connection, $command);
            stream_set_blocking($stream, true);
            $file_list = fread($stream, 8192);
            fclose($stream);
            $file_list_array = explode("\n", $file_list);
            
            return $file_list_array;
        }

最後に、status_check 関数の説明です。

status_check 関数を実行すると、最初に qstat などのコマンドでジョブ・スケジューラーの最近の実行結果内に、対象の job の job 番号が含まれているか調べます。

管理人は、torque というジョブ・スケジューラーを使っているので、Q batch が見えたら “QUE”、R batch が見えたら “RUN”、C batch が見えたら “END” のように設定しています。

次に、ジョブ・スケジューラーに job 番号が無かった場合は、ディレクトリーを移動して、対象の job の log ファイルの末尾を tail で調べます。

この時、”Normal termination” とあれば END、それ以外であれば Err となるように設定しています。

<?php
    include_once('ssh2_connection.php');
    function status_check($status, $directory, $connection, $filename, $job_number){
        if($status == 'END'){
            return 'END';
        }else{
            //$connection = connect_machine($machine_name);
            // 1. job schejuler をチェック
            $command = 'qstat | grep ' . $job_number;
            $file_list_array = connect_exec($connection, $command);

            if(count($file_list_array) > 1){
                foreach($file_list_array as $file){
                    if(strpos($file, "R batch")  !== false){
                        return 'RUN';
                    }elseif(strpos($file, "Q batch")  !== false){
                        return 'QUE';
                    }elseif(strpos($file, "C batch")  !== false){
                        return 'END';
                    }elseif(strpos($file, "E batch")  !== false){
                        return 'Err';
                    }
                }
            }

            // 2. log ファイルをチェック
            $command = 'tail ' . $directory . '/' . $filename . ' | grep -i termination';
            $file_list_array = connect_exec($connection, $command);

            if(count($file_list_array) > 1){
                foreach($file_list_array as $file){
                    if(strpos($file, 'Normal termination') !== false){
                        return 'END';
                    }elseif(strpos($file, 'Error termination') !== false){
                        return 'Err';
                    }
                }
            }else{
                return 'DNF';
            }
        }
    }
?>

第二回のまとめ

今回の記事では、非常にざっくりとではありましたが、phpMysQLGoogle Chart Tool を用いてリアルタイムで計算状況を調べるシステムを構築しました。

文字だけでは伝えきれない部分が多いですが、ソースコードを配布しているので、自分で調べながら進めてみて下さい。

将来的には youtube などで解説動画を配布することも検討しています。(youtuber になるつもりはありませんが、php + MySQL は説明する内容が多すぎて、文字だけだと厳しい。)

わからない点があれば、気軽にコメント欄して下さい。メールや DM での質問だと他の読者と共有できませんので、質問はできるだけコメント欄にお願い致します。

参考ページ

コメントを残す(投稿者名のみ必須)