如何从 Chef 食谱中的库访问当前节点?

Posted

技术标签:

【中文标题】如何从 Chef 食谱中的库访问当前节点?【英文标题】:How can I access the current node from a library in a Chef cookbook? 【发布时间】:2013-10-08 16:58:41 【问题描述】:

我正在尝试为厨师食谱编写一个库,以简化一些常见的搜索。

例如,我希望能够在 cookbook/libraries/library.rb 中执行类似的操作,然后从同一食谱中的食谱中使用它:

module Example
    def self.search_attribute(attribute_name)
        return search(:nodes, node[attribute_name])
    end
end

问题在于,在 Chef 库文件中,node 对象或 search 函数均不可用。

使用Chef::Search::Query.new().search(...) 似乎可以进行搜索,但我找不到任何可以访问node 的内容。由此产生的错误是:

undefined local variable or method `node' for Example:Module

使用 Chef 10.16.4。

【问题讨论】:

相关***.com/a/22081109/1626687 【参考方案1】:

您可以做的是将模块包含在您的食谱中。这样,您的模块函数就可以访问配方的方法,包括node

我通常为我的库模块这样做:

# my_cookbook/libraries/helpers.rb
module MyCookbook
  module Helpers
    def foo
      node["foo"]
    end
  end
end

然后,在配方中,我将模块包含到配方的当前实例中:

# my_cookbook/recipes/default.rb
extend MyCookbook::Helpers

这样,只有当前食谱会包含模块,而不是整个厨师运行中的所有模块(这样可以避免名称冲突)。

或者,您可以将当前节点作为参数传递给函数。这样,您不需要包含模块(它具有保留模块名称空间的优点),但具有更复杂的方法调用的缺点。

【讨论】:

可能是一个愚蠢的问题,但您所说的“那样,只有当前食谱包含模块,而不是整个厨师运行中的所有模块”是什么意思? 人们经常调用Chef::Recipe.include MyCookbook::Helpers,这使得辅助函数在所有配方中都可用(并且可以覆盖可能已经存在的具有相同名称的函数)。我认为这是一种代码异味,我更喜欢我的版本只将Helpers 模块明确包含在配方中。 我想我明白了。使用 Ruby 的扩展只会将模块中的方法添加到正在运行的单个配方对象中,而使用您提到的 include 会将其添加到所有 Chef::Recipe 对象中。谢谢! 对我来说,extend MyCookbook::Helpers 仍然不允许访问节点属性... @s2t2 请提出一个新问题,详细说明您尝试了什么(包括您的食谱和库代码)以及究竟出了什么问题。您可以从新问题链接到此答案以说明您的观点。【参考方案2】:

我在尝试访问库中的当前环境时遇到了这个问题。我真的不知道如何使用模块来访问节点,我不想将节点传递给每个方法调用(或实例化调用)所以我这样做了(示例代码..不是实际的功能):

# libraries/account.rb
class Account
  @@env = "_default"

  def self.env=(env)
    @@env = env
  end

  def settings
    Chef::EncryptedDataBagItem.load(@@env, "settings") || 
  end
end

# recipes/accounts.rb
Account.env = node.chef_environment

Account.new.settings

我不知道是否不赞成使用类变量,但它在我所有的测试中都有效,而且很好用。

【讨论】:

以上是关于如何从 Chef 食谱中的库访问当前节点?的主要内容,如果未能解决你的问题,请参考以下文章

Chef - 如何重新启动 VM 并继续执行操作

在 Chef 食谱中使用变量

Chef:如何覆盖角色中的默认属性?

Chef - 如何在本地运行食谱

如何控制 Vagrant 用于配置 VM 的 Chef 版本?

如何在 Chef 中自定义 tomcat 食谱