2013-10-02 30 views
5

我正在尝试为简化一些常见搜索的厨师食谱编写一个库。如何从厨师食谱的图书馆访问当前节点?

例如,我希望能够做这样的事在cookbook/libraries/library.rb,然后在相同的食谱使用它从配方:

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

的问题是,一个厨师库文件中node对象或search函数都不可用。

搜索似乎有可能通过使用Chef::Search::Query.new().search(...),但我找不到任何作品访问node。由此产生的错误是:

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

使用厨师10.16.4。

+0

相关http://stackoverflow.com/a/22081109/1626687 – spuder

回答

6

你可以做的是将模块包含在你的食谱中。这样,您的模块功能就可以访问配方的方法,包括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 

这样,只有目前的食谱包含模块,并非全部都在整个厨师中运行(因此避免了名称冲突)。

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

+0

可能是一个愚蠢的问题,但你是什么意思的“这样,只有当前的食谱获取模块包括在内,并不是全部在整个厨师跑”? –

+2

人们通常会调用'Chef :: Recipe.include MyCookbook :: Helpers',它使辅助函数在所有食谱中都可用(并且可以覆盖可能已经存在的同名的辅助函数)。我认为这是一种代码味道,并且更喜欢我的版本,以便只将'Helpers'模块明确包含在配方中。 –

+0

我想我明白了。使用Ruby的扩展只会将模块中的方法添加到正在运行的单个配方对象,而使用像您所提到的include会将它添加到所有Chef :: Recipe对象。谢谢! –

0

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

# 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 

我不知道如果使用类变量是皱眉,但它适用于我所有的测试,它很好用,易于使用。