Posted at
AkerunDay 16

LinuxシステムとNodeとのスマートな関係

More than 1 year has passed since last update.

Linuxプラットフォーム開発担当の@KoheiAkitaです。

他の弊社エンジニアも勧めているように、組み込みでNodejsを用いた開発が圧倒的にスピードが速く、去年のAdventカレンダーでNode力説記事を執筆(IoTデバイスにもスクリプト言語のススメ)してから、Nodeを使った開発を継続しています。Node熱冷めやらず。

さて、Linux上でNodeを使い続けている中で気付いたことをいくつか紹介し、Node使いの皆様にほんの少しの、いろいろな短縮に繋がれば幸いですm(_ _)m

Nodeプログラム単体で動作するのでなく、Linux上の他のシステムプロセスとのやり取りをすることをしたいケースではどうやって実装してるでしょうか。

Linuxにもきちんとイベント通知をしてくれる仕組みがあるので、イベント駆動言語のNodeとは相性が良いのです!

例えば良く使う機能のWi-Fiやデバイス検知。

Wi-FiはNICが有効になった/ネットワークが接続されたなどをプログラムから検知したいことがあるでしょう。

デバイス検知ではUSB機器が挿入された時にプログラムで処理したいことがあるでしょう。

そんな時、私は良くソケットを用いてNodeとデータのやり取りをする方法を採用しています。

例えば ネットワークがup/downした時にNode側でイベントとして受け取る方法を例に上げると、こんな感じです。


1) ソケット通信するクライアントとサーバープログラムを用意

まずは、ソケットでやり取りするNodeプログラムを用意します。単純なサンプルプログラムを示します。

client.js

var net = require('net');
var fs = require('fs');
var stream = null;

const SOCK_PATH = "/tmp/comm_node.sock";
var sockdata1 = process.argv[2];
var sockdata2 = process.argv[3];
var sockdata3 = process.argv[4];

stream = net.connect( SOCK_PATH );
stream.on('error', function(ex){
//エラー処理を記述
});
stream.on('connect', function(){
        //JSONデータで送信
stream.write( JSON.stringify(sockdata) );
stream.end();
});


server.js

const SOCK_PATH = "/tmp/comm_node.sock";
try{
//作成されていたソケットがあったら作り直し
if (fs.existsSync( socket_path )) {
fs.unlinkSync( socket_path );
}
}catch( ex ){
console.log( ex );
}

var so = net.createServer( function(stream) {
stream.on('data', function( sockdata ){
//JSONデータを受信
console.log( JSON.parse( sockdata ) );
});
});
so.listen( socket_path );


2) フックスクリプトの実装

用意したNodeスクリプトのクライアント側を、例に出したネットワークup/downのタイミングで呼ばれるスクリプトの内部に仕掛けます。

#!/bin/sh

#
# $IFACE, $MODE, $PHASEは、システムプロセスがフックスクリプトを実行する時に
# 設定する環境変数です
#
node /path/to/script/client.js $IFACE $MODE $PHASE


3) フックスクリプトを設定

2)で作成したスクリプトを、以下のフォルダに仕掛けます

ifup時に通知したい時:

/etc/network/if-up.d(or if-pre-up.d)

ifdown時に通知したい時:
/etc/network/if-down.d(or if-post-down.d)

こうすることで、ネットワークがifup/ifdownし、有効/無効になったタイミングでシステムプロセスがフックスクリプトを実行してくれるので、フックスクリプトに仕掛けたソケット通信処理を通じてNode側でもイベントとして検知でき、且つLinuxシステムプロセスとNodeプロセスとを(比較的)きれいに疎結合できるので便利です。

Linuxではメジャーなところでは、以下がシステムプロセスの動作前/動作中/動作後にスクリプトを設定することでユーザースクリプトが仕掛けられる場所です(Raspbian Stretch上調べ)。

・resolv.conf更新時

/etc/resolvconf/update.d

・ppp通信時
/etc/ppp/ip-down.d
/etc/ppp/ip-up.d
/etc/ppp/ipv6-down.d
/etc/ppp/ipv6-up.d

/etc/ifplugd/action.d
/etc/udev/rules.d

・apt-get インストール完了
/etc/kernel/postinst.d

・DHCP client処理
/etc/dhcp/dhclient-enter-hooks.d
/etc/dhcp/dhclient-exit-hooks.d

・ NIC動作変更
/etc/network/if-post-down.d
/etc/network/if-up.d
/etc/network/if-pre-up.d
/etc/network/if-down.d

これらはあくまで一部でライブラリをインストールすることで設定できるようになったり、やり方によっては無理やり設定することも可能なものもありますが、一般的なもの、を取り上げました。

NodeをLinux上で組み込む実装の参考になれば嬉しいです。