LoginSignup
13
12

More than 5 years have passed since last update.

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

Posted at

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

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

後でご説明しますが、この方法にも難があるので、他に良い方法があれば教えてください。

templateを使ってみよう

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

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

templateを準備する

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

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

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

recipeを準備する

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

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

site-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グッ!

site-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

次に、template のパートです。
ここでは、/tmp/ に中間ファイルを配置するようにしてます。=> path "/tmp/pg_chpasswd.sql"
今回は PostgreSQL で利用するので、user(owner)/group は postgres を使っています。
variables に、今回使用する pg_userpg_password の元ネタを配備しています。

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

attributeどうしよう

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

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

site-cookbooks/pgsql/attributes/default.rb
default['postgresql']['user'] = ""
default['postgresql']['password'] = ""
nodes/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 にはこんな使い方もあるんよ( ゚д゚ )クワッ!!
て感じで、どうぞ。

13
12
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
13
12