Chef/OpsWorks - передача переменных между рецептами разных Cookbok

При написании рецетов для Chef (в т.ч. Amazon OpsWorks) возникает вопрос - как передавать значения/переменные между разными рецептами, когда они из разных cookbook. Дело в том, что обычно всегда приходящее на ум сохранение в файл и с последующим чтением в другом рецепте не подойдёт. Код Chef исполняется в две стадии - сначала компиляция, а после исполнения. Он сначала считает все файлы (которые найдёт/будут доступны в это время) для всех рецептов, а после для всех выполнит. В результате вы сохраните нужную вам информацию в файл, а попытка чтения в другом получится лишь "в следующий раз" (при следующем запуске рецепта), т.к. в реальности "второй рецепт" (где вы хотели получить результаты первого) ещё раньше пытался читать файл с вашим значением, которого, понятно, тогда "ещё не было".

Это очень не очевидная ситуация, которая часто ставит в тупик и заставляет придумывать различные неадекватно странные и сложные схемы. А разрулить её можно с помощью node.run_state, например, таким образом, как это в рецепте hostname, задающем имя системы в одном кукбуке, после оно передаётся в рецепт для установки AWS Logger в другом кукбуке:

Код рецепта hostname.rb кукбука linuxcmd:

if node['my']['name'].empty?
    instance = search("aws_opsworks_instance", "self:true").first
    cur_hostname = instance['hostname']
    Chef::Log.info("*** cur_hostname is '#{cur_hostname}'")
    private_ip = instance['private_ip']
    Chef::Log.info("*** private_ip is '#{private_ip}'")
    my_site = "#{autoname}#{private_ip.split('.')[2]}-#{private_ip.split('.')[3]}.#{my_domain}"
else
    my_site = my_domain.empty? ? "#{my_name}" : "#{my_name}.#{my_domain}"
end
Chef::Log.info("*** my_site = '#{my_site}'")

node.run_state['current_hostname'] = my_site # save hostname for other recepies
Chef::Log.info("********** node.run_state['current_hostname'] (hostname) = '#{node.run_state['current_hostname']}' **********")


bash 'set hostname for current process' do
    ignore_failure = true
    code <<-EOF
        hostname '#{my_site}'
    EOF
end
# save hostname for other recepies
file '/root/current_hostname' do
    content my_site
end

Код из рецепт install.rb кукбука aws_logger:

if node.run_state['current_hostname'].to_s.empty?
    file_path = '/root/current_hostname'
    if File.exist?(file_path)
        current_hostname = File.read(file_path).strip ## strip is here for remove \n
        Chef::Log.info("********** get current_hostname from '#{file_path}' = '#{current_hostname}' **********")
    end
else
    current_hostname = node.run_state['current_hostname']
    Chef::Log.info("********** get current_hostname from node.run_state['current_hostname'] = '#{current_hostname}' **********")
end
node.default['awslogs_conf_default']['log_stream_name'] = current_hostname

Смысл простой: там, где передаём нужные данные - и сохраняем в файл и записываем в специальную переменную (хэш) node.run_state, которая создаётся на время выполнения всех рецептов и доступна им во время выполнения. В принимающем рецепте (который, понятно, должен быть после передающего) проверяем сначала, пустой ли хэш. Если нет: прекрасно, получаем и отработываем - переменная передана из одного рецепта Chef в другой, как и требовалось. Если же "принимающий" рецепт будет по вашей логике запущен после отдельно - значит он отработает через уже точно имеющийся файл с переменной на диске.

Tags: 

Если вам помогла или просто понравилась статья - плюсаните/поделитесь, пожалуйста.

Добавить комментарий