我正在将一些shell脚本迁移到Chef食谱中。其中一些脚本相当复杂,所以为了在短期内让生活更轻松,并避免在Chef/Ruby中重写所有内容时引入错误,我只想按原样运行其中一些脚本。它们都写得很好,而且是幂等的,所以说实话并不着急,但当然,最终的目标是重写它们。
Ruby的一个很酷的特性是它的__END__
关键字/方法:__END__
下面的行将不会被执行。这些行将通过特殊的文件句柄DATA提供
在__END__
之后,按照配方中的原样发送shell脚本会很酷,可能是我放在chef-repo/cookbooks/ruby-data-test/recipes/default.rb
中的以下内容:
file = Tempfile.new(File.basename(__FILE__))
file << DATA.read
bash file.path
file.unlink
__END__
echo "Hello, world"
然而,当我运行这个(使用chef-solo -c solo.rb --override-runlist 'recipe[ruby-data-test]'
)时,我会得到以下错误:
[2014-10-03T17:14:56+00:00] ERROR: uninitialized constant Chef::Recipe::DATA
我对Chef还很陌生,但我猜上面的内容是关于Chef在课堂上包装我的食谱,还有一些简单的东西阻止我访问DATA
。由于它是"全球性的"(?),我试着在它前面加一个美元符号($DATA
),但失败了:
NoMethodError
-------------
undefined method `read' for nil:NilClass
所以问题是:如何在我的厨师食谱中访问DATA
谢谢!
您似乎没有访问DATA
的权限,但您可以像Sinatra一样,通过自己读取当前文件并在__END__
上进行拆分来伪造它。
我最终制作了一个厨师LWRP以供重复使用。我不知道我是否真的会使用这个,但我想弄清楚。就像我说的,我是一个厨师/Ruby noob,所以欢迎任何更好的想法或建议!
ruby_data_test/recipes/default.rb
:
ruby_data_test_execute_ruby_data __FILE__
__END__
#!/bin/bash
set -o errexit
date
echo "Hello, world"
ruby_data_test/resources/execute_ruby_data.rb
:
actions :execute_ruby_data
default_action :execute_ruby_data
attribute :source, :name_attribute => true, :required => true
attribute :args, :kind_of => Array
attribute :ignore_errors, :kind_of => [TrueClass, FalseClass], :default => false
ruby_data_test/providers/execute_ruby_data.rb
:
def whyrun_supported?
true
end
use_inline_resources
action :execute_ruby_data do
converge_by("Executing #{@new_resource}") do
Chef::Log.info("Executing #{@new_resource}")
file_who_called_me = @new_resource.source
io = ::IO.respond_to?(:binread) ? ::IO.binread(file_who_called_me) : ::IO.read(file_who_called_me)
app, data = io.gsub("rn", "n").split(/^__END__$/, 2)
data.lstrip!
file = Tempfile.new('execute_ruby_data')
file << data
file.chmod(0755)
file.close
exit_status = ::Open3.popen2e(file.path, *@new_resource.args) do |stdin, stdout_and_stderr, wait_thr|
stdout_and_stderr.each { |line| puts line }
wait_thr.value # exit status
end
if exit_status != 0 && !@new_resource.ignore_errors
throw RuntimeError
end
end
end
这是输出:
$ chef-solo -c solo.rb --override-runlist 'recipe[ruby_data_test]'
Starting Chef Client, version 11.12.4
[2014-10-03T21:50:29+00:00] WARN: Run List override has been provided.
[2014-10-03T21:50:29+00:00] WARN: Original Run List: []
[2014-10-03T21:50:29+00:00] WARN: Overridden Run List: [recipe[ruby_data_test]]
Compiling Cookbooks...
Converging 1 resources
Recipe: ruby_data_test::default
* ruby_data_test_execute_ruby_data[/root/chef/chef-repo/cookbooks/ruby_data_test/recipes/default.rb] action execute_ruby_dataFri Oct 3 21:50:29 UTC 2014
Hello, world
- Executing ruby_data_test_execute_ruby_data[/root/chef/chef-repo/cookbooks/ruby_data_test/recipes/default.rb]
Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 1.387608 seconds