インフラエンジニア歴6年、js歴6年(業務での利用経験なし)の私が「JavaScriptでインフラの構成管理、テスト、運用自動化を実現する」というビジョンをかかげ Submarine.jsというフレームワークの開発に着手して1年が経ちました
まだまだ普及はしていませんが、少しずつ宣伝活動をしつつアップデートも重ね、v2.0.0のリリースに至りました
基本的なデザインはAnsibleとの比較で以前こちらに記載させていただきました
今回は、より高機能になったSubmarine.jsで、どんなことができるようになったのかを紹介していきます
サーバの状態と、そのテスト結果をブラウザに表示
Submarine.jsの特徴として、サーバの状態を取得するShellScript、取得した値をテストする関数( 状態の参照 のみの処理)、とサーバに 変更 を加えるShellScriptを、JavaScript上で明確に分離するというものがあります(詳細はこちらの記事)
参照と変更を分離しているからこそ 「参照」 部分に関してはJSON形式でHTTPレスポンスとして返すこともできるし、HTMLに値を埋め込んでブラウザ表示させることもできます
#osc19tk 本日も展示中
— 入水岬@インフラエンジニア (@Mjusui) November 24, 2019
ERROR画面のCSSにこだわったのであえて左端に表示 pic.twitter.com/i9SeNf5KTa
上のTweetはオープンソースカンファレンスのブースにて展示していた画面のキャプチャです。左からサーバへのコマンド実行が失敗したときの画面、成功したときの画面、オフィシャルページになります。真ん中の画面では、サーバから取得したShellScriptの実行結果と、それらをテストした結果、さらに実行したShellScriptの中身が見られます
- この機能を使えば、何か障害が起きたときに 「よく分からないけど、ひとまずここを見て、テストが失敗していないか確認する」 ということができます
- ShellScriptと、その実行結果をHTTPで公開できるので インフラエンジニアのポートフォリオ としても使えるかもしれません
あるサーバの状態と、別のサーバの状態を複合的にテストする
例えば、サーバが3台あり 「それらのディスクサイズの合計が一定値以上であること」 をテストしたいとき、1台のサーバから取得できる状態だけでは、テストはできません
サーバ全台分のディスクサイズを取得して、それらを合計した値に対して、テストをしなければなりません
こういったケースに対応するためSubmarine.js v2.xでは collaborate
という機能が追加されています
サンプルコードを見てみましょう
(1) サーバ1台からディスクサイズを取得するクラスです
const Submarine=require('Submarine');
const GetVolSize=class extends Submarine {
query(){
return {
volkb_sizes: String.raw`
df -P \
|grep -v "^Filesystem" \
|awk '{print $3+$4}'
`,
};
}
format(stats){
return {
volkb_largest: stats.volkb_sizes
.split(/\r\n|\r|\n/)
.sort(
(a, b) => b*1 - a*1
)[0], // largest volume is chosen.
};
}
test(r){
const { stats }=r;
return {
size_enough:
2 * 1024 * 1024 < stats.volkb_largest,
};
}
}
(2) (1)のクラスを複数サーバで実行できるようクラス化
const GetVolSizes=Submarine.collect(
host => new GetVolSize({
conn: 'ssh',
host: host,
}),
{ type: 'gen',
coll: 'bash',
cmd: 'echo server{1..5}', },
{ type: 'fil',
coll: 'func',
func: hosts => hosts.filter(
host => host.match(/[2-4]$/)
), },
{ type: 'fil',
coll: 'ping', }
);
(3) サーバ全台のディスクサイズの合計値をテストするクラス
test
関数内で collabs
という値が利用できます
この collabs
の中には、次の(4)の collaborate
関数に渡された、サーバ3台分のインスタンスから取得した状態が含まれています
const TestTotalVolSize=class extends Submarine {
test(r){
const { collabs }=r;
return {
each_size_enough:
collabs.every(
collab => collab.exams.ok
),
total_size_enough:
4 * 1024 *1024 < collabs.reduce((siz, collab)=>{
return siz + collab.stats.volkb_largest;
}, 0), // larger than 4MB
};
}
}
(4) (3)をインスタンス化し collaborate
関数に(2)のインスタンスを渡す
const enough=new TestTotalVolSize({
conn: 'sh',
}).collaborate(
new GetVolSizes()
);
enough.check()
.then(
r => JSON.stringify(r)
).then(console.log)
.catch(console.error)
.finally(
_ => enough.close()
);
こうすることで test
関数の中で、他のサーバ群の test
結果が使えるようになり、より複合的なテストができるようになります