Help us understand the problem. What is going on with this article?

Chefのレシピでsed的な事を実施

More than 3 years have passed since last update.

この記事は最終更新から1年以上経過しています。 気をつけてね。

Infrastructure as Codeに感化されていざChefを使うとなった時、ちょっと既存のファイルを弄りたいだけなのにcookbookfileとかtemplateとかメンドクセって思うじゃないですか。

『ほなexecuteリソースでちょっとsedコマンドしたら…』と思う前にちょっとChef::Utilを検討しませんか。

対象ファイルとレシピ

サンプルとしてこんな2行で出来たファイルを2つ用意しました。

tmp1,tmp2
hogehoge
mogemoge

では 'tmp1'に一致した行の置換、'tmp2'では文字列の置換を実施してみます。

apply.rb
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に変更。

apply2.rb
## 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読み込み対象にしてるんですね。

参考:file — Chef Docs

#contentsがprivate_methodなのでちょっと:sendしましたがまあいいっしょ。

Result

:dry_runです、きっと目論見通りですね。

chef-apply(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(conversion)
$ 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(up_to_date)
$ 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でやるのは多分面倒くさい'無かったら追記'がメソッドとして用意されています。

Chef
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版)より。

https://github.com/pearj/cookbooks/blob/master/timezone/recipes/default.rb

  clock = Chef::Util::FileEdit.new("/etc/sysconfig/clock")
  clock.search_file_replace_line(/^ZONE=.*$/, "ZONE=\"#{node[:tz]}\"")
  clock.write_file
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした