如何在收敛时更新Chef中的节点属性?

时间:2015-07-22 14:27:21

标签: ruby chef lazy-evaluation

我正在尝试解析文件中的值,以便将其设置为在配方中使用的属性(设置为子目录名称)。

该文件从jenkins服务器下载并在ruby块中解析以获取值 - 到目前为止一直很好。但是,如果我尝试将其分配给节点属性,则它不起作用。我以为我在这里找到了答案:How to lazily evaluate an arbitrary variable with Chef,但那里提到的方法都不适用于我。我做错了什么?

ruby_block "get build number" do
  block do
    f = File.open("/tmp/MyappJenkinsBuildInfo.txt")
    f.each {|line|
      line_arr = line.split('=')
      if line_arr[0] == 'jenkins.build.number'
        node.default['myapp']['jenkins']['build'] = line_arr[1]
        break
      end
    }
    f.close
  end
end

build = DelayedEvaluator.new { node['myapp']['jenkins']['build'] }

release_dir = "#{node['myapp']['dir']['main']}/releases/#{build.call}"

这“有效”,因为没有语法错误,但#{build.call}的值是一个空字符串。该文件肯定存在,我已经测试过ruby块中的line_arr [1]获得了正确的值(在RB内部有一个puts语句)。我也尝试使用lambda代替DelayedEvaluator.new。

1 个答案:

答案 0 :(得分:1)

这里的问题是您的release_dir =行在编译时执行,ruby_block中的代码运行之前。显然,在那个时间点,build.call只会返回一个空字符串,因为设置node['myapp']['jenkins']['build']的代码尚未运行。

换句话说,配方中的代码就像这样执行:

# Compile time

ruby_block "get build number" do
  block do
    # Random stuff here that will get executed at converge time
  end
end

build = DelayedEvaluator.new { node['myapp']['jenkins']['build'] }

release_dir = "#{node['myapp']['dir']['main']}/releases/#{build.call}"

# ...

# Okay, everything's compiled. Now we converge...

f = File.open("/tmp/MyappJenkinsBuildInfo.txt")
f.each {|line|
  line_arr = line.split('=')
  if line_arr[0] == 'jenkins.build.number'
    node.default['myapp']['jenkins']['build'] = line_arr[1]
    break
  end
}
f.close

因此,要回答您的问题, 在收敛时设置节点属性。如果你这样做,你必须意识到在编译时访问该变量不可能,因为在编译时该变量尚未设置。在编译时设置变量,或者在收敛时间之前不要尝试访问它。不幸的是,你不能同时拥有两者。