问题描述
我有以下代码来确定 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_file
和 execute
资源是解压应用程序(并创建目录)的资源。在这种情况下,您似乎希望它们在编译阶段运行。
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 property。 execute
资源示例:
# 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
有了这一切,一切都在按预期运行,一切似乎都在运行。