[chef] 特定のsqlを一度だけ実行する方法 [template]

chef が便利すぎて泣けてきてる今日この頃なところで、「アレはどうするんだろう」「コレはどうやって実現するんだろう」 → 公開されているレシピ使えよ( ゚д゚ )クワッ!!

という軟弱な思考に頼らず、自ら作ったレシピでどうこうしたい同輩は多いかと思われます。 皆さんの役に立つようにというよりも、もはや自分の備忘録としか思えないような話ではありますが、chef で特定の chefを「一度だけ」実行できるようにするには、どう組み合わせたら良いかなーについて、一時的に結論が出たので、ご紹介します。

後でご説明しますが、この方法にも難があるので、他に良い方法があれば教えてください。 [amazonjs asin=”B00BSPH158″ locale=”JP” tmpl=”Small” title=”入門Chef Solo – Infrastructure as Code”]

templateを使ってみよう

sqlを記述した中間ファイルを使って、変更が発生した場合の再実行、一度実行された後の再実行の抑制ができそうです。

今回は PostgreSQL で、ユーザのパスワードを変更する SQLで試してみます。

templateを準備する

まず、template ファイルを準備しましょう。

-cookbooks/pgsql/templates/default/pg_chpasswd.sql.erb
ALTER USER <%= @pg_user %> WITH PASSWORD '<%= @pg_password %>';

一旦こんな感じで。好みに応じて、Encrypted などつけてたもうれ。

recipeを準備する

次に、これにあわせて recipe を書いてみましょう。

まず、sql を実行するための execute パートを作りましょう

-cookbooks/pgsql/recipes/default.rb
execute "pgsql-chpasswd" do
  command "su - postgres -c '/usr/bin/psql -U postgres < /tmp/pg_chpasswd.sql'"
  action  :nothing
end

command は root で実行されるはずですが、PostgreSQL の socket 接続の場合、デフォルトでは Peer 接続になっているため、Linux のユーザと、PostgreSQLのユーザが同一でないと、socket通信できないようになっています。 pg_hba.conf を適当に変更すれば良いのですが、su - postgres すれば特に問題がないので、そのままで実行できるようなコマンドを準備しました。 ここでのポイントは action :nothing として、まだじっこうさせないことですね( ´∀`)bグッ!

-cookbooks/pgsql/recipes/default.rb
template "pg_chpasswd.sql" do
  path "/tmp/pg_chpasswd.sql"
  source "pg_chpasswd.sql.erb"
  user  "postgres"
  group "postgres"
  mode  0600
  variables ({
    :pg_user => node[:postgresql][:user],
    :pg_password => node[:postgresql][:password]
 })

  notifies :run, 'execute[pgsql-chpasswd]', :immediately
end

[amazonjs asin="4798123358" locale="JP" title="PostgreSQL徹底入門 第3版"] 次に、template のパートです。 ここでは、/tmp/ に中間ファイルを配置するようにしてます。=> path "/tmp/pg_chpasswd.sql" 今回は PostgreSQL で利用するので、user(owner)/group は postgres を使っています。 variables に、今回使用する pg_userpg_password の元ネタを配備しています。

最後に notifiesexecute させるという流れです。 対応した template との差異がなければ、実行されないということになりますね。

attributeどうしよう

対象となる変数をどうするかですが、初期値は attributes へ、このの定義は rolenode を使います。

今回は attributenode で定義しています。

-cookbooks/pgsql/attributes/default.rb 
default['postgresql']['user'] = ""
default['postgresql']['password'] = ""
/pgsql.json
{
        "postgresql": {
                "user"                : "zabbix",
                "password"            : "zabbix"
        },

        "run_list":[
                        :
        ]
}

見ただけで分かるように、user = "zabbix" , password = "password" という素人定義です。

これにより、sql の中間ファイルの更新状態を見て、chef 側では、一度だけ実行される、と言うことになります。

めでたいヽ(´ー`)ノ

課題がないわけじゃない

個人的には、もうコレで十分なのですが、2つほど気がついた点があります。時と場合によっては、致命的です。

  1. /tmp/ 配下のファイルが消されたら、また実行される
  2. 中間ファイルに残っている情報は見られるかも知れない

1./tmp/ 配下のファイルが消されたら、また実行される

まんまですね。 とある rebootタイミングや cronなどで、/tmp/ 配下は clearされるように設定されていた場合、中間ファイルが削除されます。 その後に、同じレシピを実行した場合、やらなくても良い SQLが流れることになります。

2.中間ファイルに残っている情報は見られるかも知れない

今回特にそうですが、めっちゃ password が入ってバレます。 md5sum したものを入れておけば良いじゃんみたいなのはありますが、時と場合によっては SQL文すら見られたくないと言うときなどもあるかと思われます。

そんな時、いくらアクセス制御をしたところで、どうにもならない場合もあるかも知れません。ないかも知れませんが。

少なくとも、脅威が1つ増えることによって、リスクと対策は増えると言うことです。気をつけましょう。

応用編

すでに想像ついてる方がほとんどでしょうか、中間ファイルを実行させるようにすれば、コマンドを実行するようにもできるでしょう。

また、消されることをうまく使って、何度も実行することもできるかも知れません。元々の使い方ではないでしょうが('A`)

ま、template にはこんな使い方もあるんよ( ゚д゚ )クワッ!! て感じで、どうぞ。 [amazonjs asin="4434181475" locale="JP" title="シェフ vol 100―一流のシェフたち"]