Использование __END__ и DATA в рецептах Chef (для запуска устаревших сценариев оболочки)

Я переношу некоторые сценарии оболочки в рецепты Chef. Некоторые из этих скриптов довольно сложные, поэтому, чтобы облегчить жизнь в краткосрочной перспективе и избежать появления ошибок при переписывании всего на Chef/Ruby, я хотел бы просто запустить некоторые из них как есть. Все они хорошо написаны и идемпотентны, так что, честно говоря, спешки нет, но, конечно же, конечная цель — переписать их.

Одной из интересных особенностей Ruby является ключевое слово __END__. /method: Строки ниже __END__ не будут выполняться. Эти строки будут доступны через специальный файловый дескриптор DATA.

Было бы здорово отправить сценарии оболочки как есть внутри рецепта после __END__, может быть, что-то вроде следующего, которое я поместил в 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 в моем рецепте Chef? Спасибо!


person Steve Kehlet    schedule 03.10.2014    source источник
comment
Вы пробовали ::DATA.read   -  person Tejay Cardon    schedule 03.10.2014
comment
Хм, отличная идея. Я пробовал ::DATA.read, но, к сожалению, с ошибкой ERROR: uninitialized constant DATA.   -  person Steve Kehlet    schedule 03.10.2014
comment
Я думаю, что это того не стоит, комментарии в этом ответе указывают, что DATA недоступен в библиотеке, и указывает на как это делает Sinatra: он читает файл и вручную разбивает на __END__. Я мог бы сделать это или просто отправить сценарий отдельно, что в любом случае может быть лучше для подсветки синтаксиса в моей среде IDE. Но все же интересно, можно ли это сделать!   -  person Steve Kehlet    schedule 03.10.2014


Ответы (1)


Похоже, у вас нет доступа к DATA, но вы можете подделать его, самостоятельно прочитав текущий файл и разделив его на __END__, как у Синатры.

В итоге я создал Chef LWRP для повторного использования. Я не знаю, буду ли я в конечном итоге использовать это, но я хотел понять это. Как я уже сказал, я новичок в Chef/Ruby, поэтому приветствуются любые лучшие идеи или предложения!

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("\r\n", "\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
person Steve Kehlet    schedule 03.10.2014