CFEngineとUbuntuの入門チュートリアル

(For the English version click here)

CFEngineとは何ですか。CFEngineは大規模システムの管理に使用できる構成管理システムだ。その元は約束理論ということだが,それによるとすべてのものはシステムのリソースに守られる約束だという。約束とパターンを結び付きによって約束をいつ・どこで実施するか指示するのはエンジンの動作の本質だ。 CFEngineの約束は「*.cf」という拡張子を末尾にある特殊な policy files に守られてる。ネットワークの各ノードはそのファイルを中央ハブあるいはファイル自体(ハブとかネットワークがない場合)から引いて、そのコピーを保存する。当チュートリアルにエンジンのダウンロード、編集とUbutu Linuxにインストールの仕方とノーマル(ノンルート)ユーザーとして使い方の案内したい。システムの実際動作のためにルートユーザーとしてCFEngineを実行しないとできない。なぜならルートユーザーだけが全ての必要な設定変更に許可を持っているからだ。 CFEngineをダウンロードする前にその3つの依存パケージの最新バージョンを持っているか確認する。依存パケージは以下の通りだ:

  • OpenSSL – Open source Secure Sockets Layer for encryption.
  • Tokyo Cabinet (1.4.42あるいはその後のバージョン)
  • PCRE – Perl Compatible Regular Expression library.

依存パケージをインストールに必要な commands は以下の通りだ:

  • TokyoCabinet用:
    sudo apt-get install libtokyocabinet-dev
  • open SSL用:
    sudo apt-get install libssl-dev
  • 最後にPerl Regular Expressions用:
    sudo apt-get install libpcre3-dev

パケージの取得が難しい場合

apt-cache search tokyocabinet

というエントリーを検索したほうが一番いい。 依存パケージからCFEngineソースコードのダウンロードに進もう。ダウンロードのディレクトリーに進む ( /Path/To はダウンロード先のディレクトリーで、x.yはダウンロードしたバージョンの番号だ。次、順番に以下のcommandsをインプットする:

cd /Path/To/cfenfine-3.x.y
./configure
make
sudo make install

上記の ./configure はシステムがエンジンを築けるか確認し、makeはエンジンを築いて適切なディレクトリーにインストールする。 CFEngineはworking directoryという概念を使用して動作する。Linuxでルートユーザー用の既定working directoryは /var/cfengine だ。その他のユーザーの場合 ~/.cfagentで探す。CFEngineをUbuntuでノンルートユーザーとしてテストだけするつもりなのでまず、次のステップを実施する必要だ:

  • 要求したディレクトリーがない場合 ~/.cfagentにそれを作る。(僕にはあった)
    mkdir -p ~/.cfagent/inputs
    mkdir -p ~/.cfagent/bin
  • ルートCFEngineのbinの内容をコピーして、ユーザーのworking directory binに貼り付ける
    cp /var/cfengine/bin/cf-* ~/.cfagent/bin

今は例のpolicy fileを見てみよう。CFEngineのHello Worldを。このpolicy fileを ~/.cfagent/inputs に入れるのに次のcommandsを使う:

touch ~/.cfagent/inputs/test.cf
chmod 600 ~/.cfagent/inputs/test.cf
echo -e "body common control
{
bundlesequence => { \"test\" };
}
bundle agent test
{
reports:
  cfengine_3::
      \"Hello world\";
}" >> ~/.cfagent/inputs/test.cf

上記のcommandsでテストpolicy fileを作成し、そのパーミッションを変更し、公式ガイドから複写したHello world policy を貼り付ける。パーミッションを変える理由は policy files の要求だ。CFEngineを実行するユーザーだけの所属でグループとかその他にパーミッションがあればsecurity exceptionが発生してcf-promises から警報が出る。 それから policy file の構文的に正しいか確認のために cf-promises を使用する.

cf-promises -f ~/.cfagent/inputs/test.cf

正しければ画面のアウトプットが何もないけど逆の場合エラーのメッセージが表示される。 最後に policy file を実行するように cf-agent を使う。

cf-agent -f ~/.cfagent/inputs/test.cf

出力は下記のようになる:

R: Hello World

手動で cf-agent を実行したのに普通は cf engine daemon, cf-execd に一定間隔(5分は既定)で起動される。そして policy file の正しさのテストのため cf-agent が自動的に cf-promises を呼び出す。 Policy fileに進んで構文を見てみよう。

body common control 
{
bundlesequence => { "test" };
}

上記はC/C++/Java のmain() functionに似ている。本文に下記のようなbundle agent testを呼び出す。

bundle agent test  
{
reports:
  cfengine_3::
   "Hello world!";
}

約束のアトリビュートの収集だ。約束が守られたなら”Hello world!”を出力する。上記の約束の意味はシステムがCFEngineのバージョン3以上を実行すると出力が”Hello World”になるということ。 この入門ポリシーができて理解したら通常に要求される動作のポリシー作成に使えるPolicy Wizardに進める。ちょっとそれで遊んでみてCFEngineの約束の構文で実行できる動作を見るのは面白い練習になる。 今、CFEngineエージェントを詳細に見よう。でもノーマル(ノンルート)ユーザーとしてCFEngineをテストしてるのでその前pre-configurationをしたほうがいい 。

cp -R /var/cfengine/share/CoreBase/* ~/.cfagent/inputs

上記がスタンダード CFEngine policy files を現在ユーザーの動作ディレクトリーのinputs policy filesに複写する。なぜなら、cf-agent が WORKINGDIR/inputs に所属している promises.cf という既定のpolicy fileをチェックする.。 Policy file を開いたら、Hello Worldファイルと同種な構文だとみえる。

###############################################################################
#
#   promises.cf - Basic Policy for Community
#
###############################################################################
 
body common control
 
{
 
 bundlesequence => {
 
                 # Common bundles first for best practice 
                    "def",
 
                 # Design Center
                    "cfsketch_run",
 
                 # Agent buddles from here
                    "main"
                   };
 
 inputs => {
 
         # Global common bundles
            "def.cf",
 
         # Control body for all agents
            "controls/cf_agent.cf",
            "controls/cf_execd.cf",
            "controls/cf_monitord.cf",
            "controls/cf_report.cf",
            "controls/cf_runagent.cf",
            "controls/cf_serverd.cf",
 
         # COPBL/Custom libraries
            "libraries/cfengine_stdlib.cf",
 
         # Design Center
             # MARKER FOR CF-SKETCH INPUT INSERTION
             "cf-sketch-runfile.cf",
 
         # User services from here
            "services/init_msg.cf",
 
           };
 
 version => "Community Promises.cf 3.4.0";
 
}
 
###############################################################################
 
bundle agent main
{
 
 methods:
 
  any::
   "INIT MSG" usebundle => init_msg,
                comment => "Just a pre-defined policy bundled with the package",
                 handle => "main_methods_any_init_msg";
}
 
###############################################################################

最初から: body common control は policy file の本体を規定する。#で始まるものはコメントであり Hello World の例と同様に bundle sequence を呼び出す。今シーケンスの bundle 数は1つ以上だ。Bundleは同じ policy file (主ファイルを例にして)あるいはinputs=>に所属してるその他のpolicy files二規定される。Bundlesがシーケンスに呼び出されているんだが、上記の “def” は最初、”main” は最終に呼び出されている。 Inputs に所定の policy files があって、その内容はメインポリシーに含んでいる機能とか定義だ。自分のを追加してみないか。

touch ~/.cfagent/inputs/fileTest.cf
chmod 600 ~/.cfagent/inputs/fileTest.cf

以上の通り、新しいpolicy fileを作成して以下のコードをコピーしてファイルに貼り付ける。

bundle agent FileTester
{
files: #file related promise
 
"/tmp/testityfile" #promiser file
 
    create => "true",   # If the file does not exist, create it
    perms => m("600"), # Make sure that the permissions are only read/write by the owner
    edit_line => replace_or_add("","I should exist in the file"); #Search the file for the given string, if it is not found replace an empty string with it
 
reports: #also adding a report to see something in stdout
    cfengine_3::  
        "File \"testityfile\" has been edited";
}

これは単に別の bundle agent だ。まず、ファイル関連の約束だと規定する。次、promiser (約束先) file名を記入する。最後に約束の3つの属性を規定する。つまり:

  • ファイルがないなら、ファイルを作る
  • ファイルのパーミッションは600ではなければパーミッションを変える
  • ファイルの中に “I should exist in the file” がなければ空いてる””ストリングにそれを書く

今、既定 promises.cf ファイルに戻って bundle sequence に自分のbundleを作ってみよう

 bundlesequence => {
 
                 # Common bundles first for best practice 
                    "def",
 
                 # Design Center
                    "cfsketch_run",
 
                 # Agent buddles from here
                    "main",
 
                 # This is our files testing functionality
                    "FileTester"
 
                   };

できたbundleをinputsに入れてその行方を明確にする。

 inputs => {
 
         # Global common bundles
            "def.cf",
 
         # Control body for all agents
            "controls/cf_agent.cf",
            "controls/cf_execd.cf",
            "controls/cf_monitord.cf",
            "controls/cf_report.cf",
            "controls/cf_runagent.cf",
            "controls/cf_serverd.cf",
 
         # COPBL/Custom libraries
            "libraries/cfengine_stdlib.cf",
 
         # Design Center
             # MARKER FOR CF-SKETCH INPUT INSERTION
             "cf-sketch-runfile.cf",
 
         # User services from here
            "services/init_msg.cf",
         # Specify the policy file for our file testing
            "fileTest.cf"
 
           };

今、cf-agent を起動してみると tmp ディレクトリに testityfile ができ その役割は約束を守ることだ。ファイルの変更にかかわらずに cf-agent が実行する時、policy file の約束が守られてる。 Policy file に replace_or_add() があったが、標準ポリシーのライブラリー機能の例だ。すべてはinputsに含まれる cfengine_stdlib.cf に所属するんだ。つまらない例なんだけど標準ライブラリーに提供される機能は精鋭でシステムの管理に有能なツールになる。例えば:

  • edit line => set_user_field(user,field,val): “field”というフィールド番号の値を/etc/passwdのような:-field formatted fileに設定する
  • edit line => append_user_field(group,field,allusers): /etc/groupのようなファイルにユーザーを追加する

標準ライブラリの policy file で他の機能とその役割も見える。 そいうことで。上記はとても基準的なCFEngineの案内でそのツールとしての能力を表面的な説明しかできなかった。次はルートユーザーに切り替えて動いてみること。これはエンジンの対象の実行方法だから。そして外部サーバー(ハブ)からポリシーを引くのはエンジンのりそうな使用方法だ。詳細をofficial CFEngine 3 tutorialに参考ください。 時間があれば、次のCFEngineチュートリアルも書いてみたい。コメント・フィードバックがあればそれとも僕の間違いを気づければぜひ教えてください(コメントあるいは直接、メールで)。 Stay sharp!

Leave a Reply

Your email address will not be published. Required fields are marked *