在 Chef 食谱中使用变量

Posted

技术标签:

【中文标题】在 Chef 食谱中使用变量【英文标题】:Using a variable inside a Chef recipe 【发布时间】:2014-06-26 09:30:38 【问题描述】:

我正在使用 chef-cookbook-hostname 食谱来设置节点的主机名。我不希望我的主机名在属性文件中被硬编码(默认 ['set_fqdn'])。

相反,主机名将从 VM 定义 XML 文件中读取。我想出了以下默认配方,但显然变量 fqdn 没有给出值。是否知道为什么会发生这种情况或更好地完成我的任务?

ruby_block "Find-VM-Hostname" do
   block do
     require 'rexml/document'
     require 'net/http'
     url = 'http://chef-workstation/services.xml'
     file = Net::HTTP.get_response(URI.parse(url)).body
     doc = REXML::Document.new(file)
     REXML::XPath.each(doc, "service_parameters/parameter") do |element|
     if element.attributes["name"].include?"Hostname"
        fqdn = element.attributes["value"]  #this statement does not give value to fqdn
     end
     end
    end
    action :nothing
end
if fqdn
  fqdn = fqdn.sub('*', node.name)
  fqdn =~ /^([^.]+)/
  hostname = Regexp.last_match[1]

  case node['platform']
   when 'freebsd'
    directory '/etc/rc.conf.d' do
      mode '0755'
    end

    file '/etc/rc.conf.d/hostname' do
      content "hostname=#fqdn\n"
      mode '0644'
      notifies :reload, 'ohai[reload]'
     end
   else
    file '/etc/hostname' do
       content "#hostname\n"
       mode '0644'
       notifies :reload, 'ohai[reload]', :immediately
    end
   end

【问题讨论】:

【参考方案1】:

这里问题的根源是您将变量 fqdn 设置在 ruby​​_block 的范围内,并试图在编译阶段引用该变量。 ruby_block 资源允许在收敛阶段运行 ruby​​ 代码。

鉴于您似乎使用 fqdn 来设置资源集,看起来您可以从 ruby​​ 代码周围删除 ruby​​ 块。例如

fqdn = // logic to get fqdn

file '/tmp/file' do
  content "fqdn=#fqdn"
end

【讨论】:

它解决了问题并且效果很好!感谢您的快速回复。【参考方案2】:

我在 Chef 文档中找到了这个。我遇到了类似的问题。我要试试node.run_state。此信息位于本页底部https://docs.chef.io/recipes.html

在 chef-client 运行期间使用 node.run_state 存储临时数据。该数据可以在资源之间传递,然后在执行阶段进行评估。 run_state 是一个空 Hash,总是在 chef-client 运行结束时被丢弃。

例如,以下配方将安装 Apache Web 服务器,随机选择 php 或 Perl 作为脚本语言,然后安装该脚本语言:

package "httpd" do
  action :install
end

ruby_block "randomly_choose_language" do
  block do
    if Random.rand > 0.5
      node.run_state['scripting_language'] = 'php'
    else
      node.run_state['scripting_language'] = 'perl'
    end
  end
end

package "scripting_language" do
  package_name lazy  node.run_state['scripting_language'] 
  action :install
end

【讨论】:

我已经尝试过类似的方法(在 run_state 中分配一个变量并在模板中检索它)并且 node.run_state 命令总是在包调用中返回一个空值,所以这并不普遍看起来。 有run_state,忘了懒惰。谢谢!【参考方案3】:

请点击此链接 http://lists.opscode.com/sympa/arc/chef/2015-03/msg00266.html 您可以使用 node.run_state[:variables] 将一个变量解析为另一个配方

这是我的代码:: 文件.rb

node.run_state[:script_1] = "foo" include_recipe 'provision::copy'

并在其他 copy.rb 文件中放入以下代码::

copy.rb

文件名 = node.run_state[:script_1] puts "名字是#filename"

【讨论】:

【参考方案4】:

我出于同样的目的使用了node.run_state['variable'],并且成功地做到了。请在下面找到基本示例代码。

ruby_block "resource_name" do
   block do
     node.run_state['port_value'] = 1432
   end
end

ruby_block "resource_name2" do
   block do
      num = node.run_state['variable']
   end
end

我希望它会有所帮助。

【讨论】:

要在配方中获取 run_state 的值而不是用于赋值,请使用#node.run_state['variable']

以上是关于在 Chef 食谱中使用变量的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Chef 食谱中使用自定义 JSON 属性

Chef - 如何在本地运行食谱

如何在 Chef 中自定义 tomcat 食谱

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

如何使用 Ruby 块在厨师食谱中分配变量

Chef/OpsWorks:实例在新发布的 Windows 食谱版本上失败