17

シェフのレシピで少し DRY を行う最良の方法は何ですか? つまり、Ruby コードのほんの一部を分割するだけなので、何度もコピーして貼り付けるわけではありません。

もちろん、次の場合は失敗します。

NoMethodError: undefined method `connect_root' for Chef::Resource::RubyBlock

1 つのレシピに複数の ruby​​_block を含めることができます。それらは異なることを行い、真の冪等性を持たせるには異なる not_if ブロックが必要だからです。

def connect_root(root_password)
  m = Mysql.new("localhost", "root", root_password)
  begin
    yield m
  ensure
    m.close
  end
end

ruby_block "set readonly" do
  block do
    connect_root node[:mysql][:server_root_password] do |connection|
      command = 'SET GLOBAL read_only = ON'
      Chef::Log.info "#{command}"
      connection.query(command)
    end
  end
  not_if do
    ro = nil
    connect_root node[:mysql][:server_root_password] do |connection|
      connection.query("SELECT @@read_only as ro") {|r| r.each_hash {|h| 
        ro = h['ro']
      } }
    end
    ro
  end
end
4

2 に答える 2

25

すでにわかっているように、レシピで関数を定義することはできません。そのためにライブラリが提供されています。次のように、クックブックのlibrariesフォルダー内にファイル (例: mysql_helper.rb )を作成する必要があります。

module MysqlHelper
  def self.connect_root( root_password )
    m = Mysql.new("localhost", "root", root_password)
    begin
      yield m
    ensure
      m.close
    end
  end
end

クラスではなく、モジュールでなければなりません。また、静的として定義していることにも注意してください (self.method_name を使用)。次に、モジュール名とメソッド名を使用して、レシピでこのモジュールで定義された関数を使用できるようになります。

MysqlHelper.connect_root node[:mysql][:server_root_password] do |connection|
  [...]
end
于 2013-03-27T20:38:42.937 に答える
1

記録のために、次のライブラリを作成しました。しかし、それは 1 つのファイル内の DRY にはやり過ぎのようです。また、モジュールが使用する他の名前空間を取得して機能させる方法もわかりませんでした。

class Chef
  class Resource
    def connect_root(root_password)
      ...
于 2013-03-24T05:02:46.363 に答える