Ansible で複数行の文字列置換
ansible で設定ファイル内の文字列を置換したかったので、 lineinfile モジュールを試してみました。
lineinfile
http://www.ansibleworks.com/docs/modules.html#lineinfile
対象サーバに以下のようなファイルを用意。
- /tmp/test.conf
foo bar baz bar bar bar foo
このファイル内の文字列を置換してみます。
以下のような Playbook を作成しました。
- lineinfile.yml
- hosts: all user: root vars: target_file: /tmp/test.conf tasks: - name: lineinfile example task lineinfile: dest=${target_file} state=present regexp='^bar$' line=BAR=99999
ここで lineinfile モジュールに指定しているパラメータは以下のような意味です。
実行してみます。
$ ansible-playbook lineinfile.yml -i hosts -k
確認してみると以下のように、最後の "bar" だけが置換されている事がわかります。
# cat /tmp/test.conf foo bar baz bar bar BAR=99999 foo
複数行まとめて置換したい場合はどうやるんだろう?と思ってドキュメントを確認したところ、以下のように書いてありました。
only the last line found will be replaced.
http://www.ansibleworks.com/docs/modules.html#lineinfile
どうやら lineinfile モジュールでは、複数行マッチした場合は最後にマッチした行のみ置換されるようです。
他にも同じくドキュメントに
This is primarily useful when you want to change a single line in a file only. For other cases, see the copy or template modules.
http://www.ansibleworks.com/docs/modules.html#lineinfile
と書いてあったりするので、どうやら今のところ複数行の置換には対応していない模様(バージョン 1.2.2 で確認)。
とはいえ template を用意するほど変更箇所が多いわけでもないし・・・。
というわけで、結局 command モジュール + sed で以下のようにしました。
- hosts: all user: root vars: target_file: /tmp/test.conf tasks: - name: find and replace using sed command: sed -i "s/^bar$/BAR=99999/g" ${target_file}
変更後に再度実行すると全て置換されている事が分かります。
# cat /tmp/test.conf foo BAR=99999 baz BAR=99999 BAR=99999 BAR=99999 foo
置換系は sed 使えば確かに簡単なので、当面これでいいような気がしました。
マッチしなければ何も起きないので、冪等性が壊れることも多分無さそうだし。
参考:
lineinfile モジュール
http://yteraoka.github.io/ansible-tutorial/ansible-in-detail.html#module-lineinfile
ちょうど今月の Software Design が sed 特集みたいです。