LoginSignup
0
0

More than 3 years have passed since last update.

JavaScriptとShellScriptで、プログラマブルなインフラを実現する

Posted at

インフラエンジニア歴6年、js歴6年(業務での利用経験なし)の私が「JavaScriptでインフラの構成管理、テスト、運用自動化を実現する」というビジョンをかかげ Submarine.jsというフレームワークの開発に着手して1年が経ちました

まだまだ普及はしていませんが、少しずつ宣伝活動をしつつアップデートも重ね、v2.0.0のリリースに至りました

基本的なデザインはAnsibleとの比較で以前こちらに記載させていただきました

今回は、より高機能になったSubmarine.jsで、どんなことができるようになったのかを紹介していきます

サーバの状態と、そのテスト結果をブラウザに表示

Submarine.jsの特徴として、サーバの状態を取得するShellScript、取得した値をテストする関数( 状態の参照 のみの処理)、とサーバに 変更 を加えるShellScriptを、JavaScript上で明確に分離するというものがあります(詳細はこちらの記事)

参照と変更を分離しているからこそ 「参照」 部分に関してはJSON形式でHTTPレスポンスとして返すこともできるし、HTMLに値を埋め込んでブラウザ表示させることもできます

上のTweetはオープンソースカンファレンスのブースにて展示していた画面のキャプチャです。左からサーバへのコマンド実行が失敗したときの画面、成功したときの画面、オフィシャルページになります。真ん中の画面では、サーバから取得したShellScriptの実行結果と、それらをテストした結果、さらに実行したShellScriptの中身が見られます

  • この機能を使えば、何か障害が起きたときに 「よく分からないけど、ひとまずここを見て、テストが失敗していないか確認する」 ということができます
  • ShellScriptと、その実行結果をHTTPで公開できるので インフラエンジニアのポートフォリオ としても使えるかもしれません

あるサーバの状態と、別のサーバの状態を複合的にテストする

例えば、サーバが3台あり 「それらのディスクサイズの合計が一定値以上であること」 をテストしたいとき、1台のサーバから取得できる状態だけでは、テストはできません

サーバ全台分のディスクサイズを取得して、それらを合計した値に対して、テストをしなければなりません

こういったケースに対応するためSubmarine.js v2.xでは collaborate という機能が追加されています

サンプルコードを見てみましょう

(1) サーバ1台からディスクサイズを取得するクラスです

Collaborate-with-other-servers.js
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)のクラスを複数サーバで実行できるようクラス化

Collaborate-with-other-servers.js
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台分のインスタンスから取得した状態が含まれています

Collaborate-with-other-servers.js
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)のインスタンスを渡す

Collaborate-with-other-servers.js
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 結果が使えるようになり、より複合的なテストができるようになります

Submarine.jsを使ってみたいという方へ

オフィシャルページはこちらになります
全機能の使い方のTutrialはこちらになります

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0