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

How to update a node attribute in Chef at converge time?

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

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

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}"

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

这里的问题是你的 release_dir = 行在编译时被执行, 你的 ruby_block 中的代码有 运行 .显然在那个时间点,build.call 只是去 return 一个空字符串,因为设置 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

因此,为了回答您的问题,您在收敛时设置节点属性。如果你那样做,你必须意识到在编译时不可能访问那个变量,因为在编译时甚至还没有设置变量。要么在编译时设置变量,要么在收敛时不要尝试访问它。不幸的是,你不能两者兼得。