この記事は最終更新から1年以上経過しています。 気をつけてね。
Infrastructure as Code
に感化されていざChefを使うとなった時、ちょっと既存のファイルを弄りたいだけなのにcookbook
にfile
とかtemplate
とかメンドクセって思うじゃないですか。
『ほなexecute
リソースでちょっとsedコマンドしたら…』と思う前にちょっとChef::Util
を検討しませんか。
対象ファイルとレシピ
サンプルとしてこんな2行で出来たファイルを2つ用意しました。
hogehoge
mogemoge
では 'tmp1'に一致した行の置換、'tmp2'では文字列の置換を実施してみます。
file './tmp1' do
_file = Chef::Util::FileEdit.new(path)
_file.search_file_replace_line('^hoge', "piyopiyo\n")
content _file.send(:contents).join
end
file './tmp2' do
_file = Chef::Util::FileEdit.new(path)
_file.search_file_replace('ge', "ga")
content _file.send(:contents).join
end
追記中:Chef-Clientが11.12以降では FileEditの@contentsがなくなり、@editor.linesに変更。
## 11.12.0以降のクライアント
file './tmp1' do
_file = Chef::Util::FileEdit.new(path)
_file.search_file_replace_line('^hoge', "piyopiyo\n")
content _file.send(:editor).lines.join
end
file './tmp2' do
_file = Chef::Util::FileEdit.new(path)
_file.search_file_replace('ge', "ga")
content _file.send(:editor).lines.join
end
Chef::Util::FileEdit.new(path)
のpath
について。
レシピのリソース定義内では自分(self)のattributes
を利用することができるので、path(※省略時はnameと同じ)を使いまわしてChef::Util::FileEdit
読み込み対象にしてるんですね。
#contents
がprivate_methodなのでちょっと:send
しましたがまあいいっしょ。
Result
:dry_run
です、きっと目論見通りですね。
$ chef-apply appry.rb -w
Recipe: (chef-apply cookbook)::(chef-apply recipe)
* file[./tmp1] action create
- Would update content in file ./tmp1 from 639ed8 to 55d5ca
--- ./tmp1 2013-08-20 00:45:11.000000000 +0900
+++ /var/folders/s9/kwcs_8ln0d32v_n4hdfb7td00000gn/T/.tmp120130820-24879-gemfn5 2013-08-20 00:45:19.000000000 +0900
@@ -1,2 +1,2 @@
-hogehoge
+piyopiyo
mogemoge
* file[./tmp2] action create
- Would update content in file ./tmp2 from 639ed8 to 93260c
--- ./tmp2 2013-08-20 00:45:03.000000000 +0900
+++ /var/folders/s9/kwcs_8ln0d32v_n4hdfb7td00000gn/T/.tmp220130820-24879-ieq0kc 2013-08-20 00:45:19.000000000 +0900
@@ -1,2 +1,2 @@
-hogehoge
-mogemoge
+hogahoga
+mogamoga
実施します、まあ:dry_run
と変わらず。
$ chef-apply appry.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
* file[./tmp1] action create
- update content in file ./tmp1 from 639ed8 to 55d5ca
--- ./tmp1 2013-08-20 00:45:11.000000000 +0900
+++ /var/folders/s9/kwcs_8ln0d32v_n4hdfb7td00000gn/T/.tmp120130820-24938-1bwvf6g 2013-08-20 00:45:41.000000000 +0900
@@ -1,2 +1,2 @@
-hogehoge
+piyopiyo
mogemoge
* file[./tmp2] action create
- update content in file ./tmp2 from 639ed8 to 93260c
--- ./tmp2 2013-08-20 00:45:03.000000000 +0900
+++ /var/folders/s9/kwcs_8ln0d32v_n4hdfb7td00000gn/T/.tmp220130820-24938-h5bq4k 2013-08-20 00:45:41.000000000 +0900
@@ -1,2 +1,2 @@
-hogehoge
-mogemoge
+hogahoga
+mogamoga
続いてchef-apply
実施、もうファイルに対して残す変更はありません。
$ chef-apply appry.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
* file[./tmp1] action create (up to date)
* file[./tmp2] action create (up to date)
よし、本日も冪等である。
その他FileEditのメソッド
その他sedでよく使うマッチ行の次に挿入や、sedでやるのは多分面倒くさい'無かったら追記'がメソッドとして用意されています。
pry(main)> Chef::Util::FileEdit.instance_methods(false)
=> [:search_file_replace_line,
:search_file_replace,
:search_file_delete_line,
:search_file_delete,
:insert_line_after_match,
:insert_line_if_no_match,
:write_file]
Chef::Util
のあたりChefの中でもかなり古いコードです、初期はファイルをちょろっといじるようなツールだったのでしょうかね。
追記:
念のため書いておくとChef::Util::FileEdit
本来の使い方は#write_file
で、Chef::Util::Backup
などと組み合わせて主にLibraryやLWRP方面で利用します。
ただレシピ内でやるのは芸が無いと思うのです。
追記2:
普通の使い方のサンプルも引用しておきます。
timezone cookbook(fork版)より。
clock = Chef::Util::FileEdit.new("/etc/sysconfig/clock")
clock.search_file_replace_line(/^ZONE=.*$/, "ZONE=\"#{node[:tz]}\"")
clock.write_file