2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

単純な冪等性にかわる新しい哲学が、構成管理には必要だという話

Posted at

先日、個人開発のOSS - Submarine.jsのv1.0をリリースしました 記事はこちら

Ansibleの冪等性に関する Tweet が、結構な反応をいただけたこともあり、今回は、私がSubmarine.jsで克服したかった「冪等性の限界」と、それを、どのような哲学で解決しようとしているかについて、説明しようと思います

冪等性の理想と現実

そもそも冪等性とは? という話は、各所で説明されていることなので簡単に

  • 冪等性とは
    • 同じ操作を何回実行しても、同じ結果が得られること
    • インフラの構成管理の世界では、何回同じコードを実行しても、同じサーバの状態が得られるという意味で使われる
    • Webの世界ではHTTPのGETやPUTメソッドは冪等だけど、POSTは冪等ではないなどと言われる

Ansibleでは、この冪等性を簡単に実現するために、目的に応じて膨大な数のモジュールが提供されています

Ansibleを使って構成管理をしているプロジェクトでは、これら膨大なモジュール群の中から、自分のやりたいことに合ったモジュールを探して、組み合わせて利用します

ところが、意外と自分のほしい機能がない(あるいは見つからない)ことがあり、そういうときにはshellモジュールなどを使って、冪等なコードを自前で書く必要があります

この「冪等なコード」というのが、結構複雑になりがちで、レビューやメンテナンスがしづらかったり、バグの温床になったりします

冪等なコードを書くために必要なこと

前述のように冪等性というのは、構成管理をする上で理想的な考えではあるけれども、実装上の困難が多いのも事実です

そもそも冪等なコードを実現するためには、以下のような3つの要件を、1度に実現する複雑な処理が必要です

多くのことを1度にやろうとすると、大体うまくいかないものです

Submarine.jsのアプローチ

Submarine.jsでは、まず上記の冪等なコードに必要な処理を、1度に実行するのではなく明確に分割しようと考え、現在の状態の確認手段を query、あるべき状態の定義(と確認)を test、状態を移行するための手段を command、として1つのクラスのメソッドとして定義できるようにしました

Correct-server-state-with-ssh.js
const Submarine=require('Submarine');

const CorrectServerState=class extends Submarine {
  query(){
    return {
      file_content: String.raw`
        test -r /tmp/submarine/hogehoge \
          && cat /tmp/submarine/hogehoge \
          || echo 'File not readable' \
            >&2
      `,
    };
  }

  test(stats){
    return {
      file_content_is_hogehoge: stats.file_content === 'hogehoge',
    };
  }

  command(){
    return String.raw`
      mkdir -p /tmp/submarine \
        && echo 'hogehoge' \
          > /tmp/submarine/hogehoge
    `;
  }
 

}


const state=new CorrectServerState({
  conn: 'ssh',
  host: 'server1',
});
    


state.correct()
  .then(console.log);

上記のコードで query は、キーと値のセットを返します。値はサーバの状態を確認するShellScriptの文字列で、キーは単なる名前です
testquery で定義したShellScript群の実行結果が引数として与えられ、それらが、あるべき状態か否かの複数の判定項目を判定して、判定結果をキーと値で返します
そして command では、判定結果に応じて実行したいShellScriptを文字列として返します

こうして定義されたclassをnewするときに接続先のホストを指定して correct 関数を実行すると query を実行し、その結果を test し、あるべき状態でないときだけ command で定義したShellScriptが実行されるようになっています

また command を実行せず query だけ、あるいは querytest だけを実行する関数も用意されています ( currentcheck という関数です)

当然、これらの処理を複数のサーバで実行する方法や、複数classの処理を順番に実行するような機構もあります(ここでの説明は割愛しますが)

こうすることで、冪等なコードに一定の秩序が生まれます。Shellの中に書くif文もかなり減らせます。しかもサーバの状態を確認する処理と、サーバに変更を加える処理が分離されたことで、変更の処理が実行されるかどうかを安全に確認でき、メンテナンス性も向上しています。

また command を実装せず、テストのためだけに利用するなど、応用範囲も広がります

その他、開発の経緯など

このSubmarine.jsのアイディアは、オブジェクト指向の世界で、CQS(コマンドとクエリの分離)や、その発展形であるCQRS(コマンド・クエリ責務分離)と呼ばれている考え方に触発されたものです

またJavaScriptを使って状態を管理するのはReact.jsやVue.jsに影響を受けています

HTTPの世界でGETやPUTとPOSTが明確に分けられていたり、データベースの世界ではCRUDのような概念があるように、インフラの世界でも「状態」を扱うのに適したフレームワークがあっても良いかなと思って開発してみました

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?