厨师在红宝石块中使用cookbook_file

问题描述

我有以下代码来确定 Java 在盒子上的位置。 Java 随我们的应用程序一起提供,应用程序随附的 Java 版本有所不同。

def app_java_home
  if Dir.exist?("#{app_home}/jre-server/linux")
    Dir.chdir("#{app_home}/jre-server/linux") do
      Dir.glob('jdk*').select { |f| File.directory? f }[0]
    end
  end
end

然后,在我的食谱中

aws_s3_file "#{app_download_path}/#{app_s3['archive_file']}" do
  bucket app_s3['bucket']
  remote_path app_s3['remote_path']
  region aws_region
  not_if { ::Dir.exists?(app_bin_dir) }
  not_if { ::File.exists?("#{app_download_path}/#{app_s3['archive_file']}") }
end

execute 'extract' do
  user 'root'
  command "unzip #{app_download_path}/#{app_s3['archive_file']} > /dev/null"
  not_if { ::Dir.exists?("#{app_home}/ourapp") }
  only_if { ::File.exists?("#{app_download_path}/#{app_s3['archive_file']}") }
end

execute 'move' do
  user 'root'
  command "mv #{app_download_path}/ourapp/ #{app_install_path}"
  not_if { ::Dir.exists?(app_home) }
end

cookbook_file "#{app_java_home}/jre/lib/security/local_policy.jar" do
  source %W[#{app_release}/local_policy.jar default/local_policy.jar]
  owner app_user_name
  group app_group_name
  mode 0755
end

cookbook_file "#{app_java_home}/jre/lib/security/US_export_policy.jar" do
  source %W[#{app_release}/US_export_policy.jar default/US_export_policy.jar]
  owner app_user_name
  group app_group_name
  mode 0755
end

然而,这两个cookbook_file资源因为找不到目录而失败:

No such file or directory @ dir_chdir - /ourapp/jre-server/linux/

经过大量谷歌搜索后,我得出的结论是配方的编译时间和运行时间之间存在..“不匹配”(?)。基本上,如果我理解正确,它会先尝试运行 cookbook_file 资源但失败了。所以永远不要下载、解压和安装应用程序。

我尝试在目录存在时运行 app_java_home,它似乎按我想要的方式工作..

我尝试将 cookbook_file 资源放在 ruby_block 中,但后来我得到了:

undefined method `cookbook_file' for Chef::Resource::RubyBlock

app_java_home .. 函数 (?) 以前看起来像这样:

def app_java_home
  "#{app_home}/jre-server/linux/#{jdk_version}"
end

jdk_version 来自数据包的位置。这工作得很好,但是我们的系统中有一个长期存在的错误/功能请求,有时会发生“他们”将他们放入数据包中的版本错误,导致各种问题..所以他们想要一种方法删除这个依赖,而不是动态地“弄清楚”。

Ruby 和 Chef 不是我的强项,所以我不确定接下来要尝试什么。我找到了对 Chef::Resources::CookbookFile 的引用(如果我理解它,可以/应该在 ruby_block 中使用),但找不到任何关于它的示例或文档。 RubyDocs 上的链接已损坏。

解决方法

在此处添加答案以获得更好的解释。

  • 任何不在任何 Chef 资源中的 (Ruby) 代码都将在编译阶段运行

  • 所有资源声明都将按照定义的顺序在收敛阶段运行

幸运的是,如果需要,有一种方法可以使资源在编译阶段运行。虽然恕我直言,但在特殊情况下应该谨慎行事。

根据您的评论,aws_s3_fileexecute 资源是解压应用程序(并创建目录)的资源。在这种情况下,您似乎希望它们在编译阶段运行。


Chef 客户端 16.0 之前

run_action 选项与应在编译时执行的操作一起使用。例如 execute 资源采取行动 :run

# Note action ":nothing" and "run_action"

execute 'extract' do
  user 'root'
  command "unzip #{app_download_path}/#{app_s3['archive_file']} > /dev/null"
  not_if { ::Dir.exists?("#{app_home}/ourapp") }
  only_if { ::File.exists?("#{app_download_path}/#{app_s3['archive_file']}") }
  action :nothing
end.run_action(:run)

Chef 客户端 16.0 及以上

我们可以为资源添加一个 common propertyexecute 资源示例:

# Note the extra property "compile_time"

execute 'extract' do
  user 'root'
  command "unzip #{app_download_path}/#{app_s3['archive_file']} > /dev/null"
  not_if { ::Dir.exists?("#{app_home}/ourapp") }
  only_if { ::File.exists?("#{app_download_path}/#{app_s3['archive_file']}") }
  compile_time true
end

最后回答问题:

厨师在红宝石块中使用cookbook_file

这是不可能的。请参阅顶部的第一点。如果我们希望 Ruby 代码在收敛(而不是编译)期间运行,我们将它放在 ruby_block 资源中。所以它可以包含如下代码(例如):

ruby_block 'get directory' do
  block do
    def app_java_home
      "#{app_home}/jre-server/linux/#{jdk_version}"
    end
  end
end
,

在@seshadri_c 的帮助下,我终于解决了问题!花了一些时间,因为我一直在误解建议等。

所以这就是我想出来的(为了后代):

return render_template(page_name)

结果我只需要单独获取版本,所以我重新安排了一些功能。我相信它可以写得更简洁,但这里的技巧是使用 def jdk_version(required = true) base_dir = "#{app_home}/jre-server/linux" if Dir.exist?("#{base_dir}") Dir.chdir("#{app_home}/jre-server/linux") do Dir.glob("jdk*").each do |f| if File.directory?(f) return "#{f}" end end end end end def app_java_home return "#{app_home}/jre-server/linux/#{jdk_version}" end 而不是 return!好吧,我是一名程序员,但不是 Ruby 程序员,所以不知道这是一个选择..

然后,在食谱中,我在需要的地方添加了 puts/print.run_action() 不需要它们,这简化了一些事情:

cookbook_file

有了这一切,一切都在按预期运行,一切似乎都在运行。