【问题标题】:DRY within a Chef recipe在厨师食谱中干燥
【发布时间】:2013-03-24 04:25:36
【问题描述】:

在厨师食谱中做一点 DRY 的最佳方法是什么? IE。只需分解一点点 Ruby 代码,所以我不会一遍又一遍地复制粘贴它。

以下当然失败了:

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

我可能在一个配方中有多个 ruby​​_blocks,因为它们做不同的事情并且需要有不同的 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

【问题讨论】:

    标签: ruby chef-infra chef-recipe


    【解决方案1】:

    正如您已经知道的那样,您不能在配方中定义函数。为此提供了库。您应该在食谱的 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
    

    【讨论】:

    • 我没有尝试过,但它是一个完整的答案,例如。谢谢!我很遗憾地看到我必须为一个不会在其他任何地方使用的小功能创建一个完整的厨师食谱库。但无论如何。
    • 如果你想使用实例方法,这样你就不必在类名前面加上前缀,你只需::Chef::Recipe.send(:include, MysqlHelper),然后你可以直接调用connect_root
    • 谢谢@JohnMorales。接受的答案是完美的,但是您添加的行(如下所示)使其工作完成: ::Chef::Recipe.send(:include, MysqlHelper)
    • 如果你想在 recipes 中使用模块实例方法,你可以在你的 recipe 中添加 extend MysqlHelper 行,然后 MysqlHelper 的所有实例方法都可以在这个 recipe 中使用。调用 include 会将这些方法添加到每个配方中,这有时过于宽泛。
    • 我正在使用 ChefDK v0.16.28 并且能够在食谱中定义方法。似乎这在过去几年中可能发生了变化。
    【解决方案2】:

    为了记录,我刚刚创建了一个包含以下内容的库。但这对于一个文件中的 DRY 来说似乎有点过分了。我也不知道如何让模块使用任何其他命名空间来工作。

    class Chef
      class Resource
        def connect_root(root_password)
          ...
    

    【讨论】:

    • 厨师食谱中的库文档严重不足且非常模糊。
    • 您不应该对资源类进行猴子补丁。最好是创建一个模块并通过模块寻址方法。
    猜你喜欢
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多