在Chef配方中使用__END__和DATA(运行遗留shell脚本)



我正在将一些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

最新更新