Boa pergunta - os dois exemplos funcionam da maneira que eu esperaria, mas não é imediatamente óbvio o motivo.
Como StephenKing escreveu em sua resposta, a primeira coisa a entender é que as receitas são compiladas (para produzir um conjunto de recursos) e, em seguida, os recursos são convergidos (para efetuar alterações em seu sistema). Estas duas fases são frequentemente intercaladas - alguns dos seus recursos podem ser convergidos antes de o Chef terminar de compilar todas as suas receitas. Erik Hollensbe cobre isso com algum detalhe em sua postagem "The Chef Resource Run Queue" .
Aqui está seu primeiro exemplo novamente:
ruby_block "block1" do
block do
puts "in block1"
end
action :create
end
remote_file "/tmp/foo" do
puts "in remote_file"
source "https://yahoo.com"
end
Estes são os passos que o Chef irá seguir ao processar esse exemplo.
- Primeiro, a declaração ruby_block é compilada, o que resulta em um recurso chamado
ruby_block[block1]
sendo adicionado à coleção de recursos. O conteúdo do bloco (a primeira instruçãoputs
) ainda não foi executado - ele é salvo para ser executado quando esse recurso for convergido. - Em seguida, a declaração remote_file é compilada. Isso resulta em um recurso chamado
remote_file[/tmp/foo/]
sendo adicionado à coleção de recursos, com uma fonte de " link ". No processo de compilação dessa declaração, a segunda instruçãoputs
será executada - isso tem efeito colateral de imprimir "em remote_file", mas não afeta o recurso que é colocado na coleção de recursos. - Com mais nada para compilar, o Chef começa a convergir os recursos na coleção de recursos. O primeiro é
ruby_block[block1]
e Chef executa o código ruby no bloco - imprimindo "no bloco1". Depois de terminar a execução do bloco, ele registra uma mensagem dizendo que o recurso foi chamado. - Finalmente, o Chef converge
remote_file[/tmp/foo]
. Novamente, ele registra uma mensagem (ou duas) associada a essa atividade.
Isso deve produzir a seguinte sequência de saída:
- Nada é impresso quando o ruby_block é compilado.
- "em remote_file" será impresso enquanto o remote_file é compilado.
- "no bloco1" será impresso enquanto o ruby_block estiver convergido.
- Uma mensagem de registro do Chef será impressa depois que o ruby_block for convergido.
- Outras mensagens de registros do Chef serão impressas durante / depois que o remote_file for convergido.
No seu segundo exemplo:
ruby_block "block1" do
block do
node.default['test'] = {}
node.default['test']['foo'] ='https://google.com'
puts "in block1"
end
action :create
end
remote_file "/tmp/foo" do
puts "in remote_file"
source node.default['test']['foo']
end
Como no primeiro exemplo, não esperamos que nada seja impresso enquanto o ruby_block é compilado - todo o "bloco" é salvo e seu conteúdo não será executado até que o recurso seja convergido.
A primeira saída que vemos é "in remote_file", como a instrução puts
é executada quando Chef compila o recurso remote_file. Na linha seguinte, definimos o parâmetro source
para o valor de node.default['test']['foo']
, que aparentemente é {}
. Esse não é um valor válido para source
, então a execução do Chef termina nesse ponto - antes que o código em ruby_block
seja executado.
Portanto, a saída esperada desta receita é:
- Nenhuma saída ao compilar o ruby_block
- "no remote_file" impresso durante a compilação do remote_file
- Um erro devido ao parâmetro
source
inválido
Espero que isso ajude você a entender o comportamento que está vendo, mas ainda temos um problema para resolver.
Embora você tenha perguntado "como eu posso forçar o ruby_block a ser executado primeiro?", seu comentário para StephenKing sugere que isso não é realmente o que você quer - se você realmente quer que o bloco seja executado primeiro, você pode colocá-lo diretamente no seu código da receita. Como alternativa, você pode usar o método .run_action () forçar o recurso a ser convergido assim que for compilado - mas você diz que ainda há mais recursos que precisam convergir antes que o ruby_block possa ser útil.
Como vimos acima, os recursos não são "executados", são primeiro "compilados" e "convergidos". Com isso em mente, o que você precisa é que o recurso remote_file
use alguns dados que não são conhecidos quando compilados, mas que serão conhecidos quando forem convergidos. Em outras palavras, algo como o parâmetro "block" no ruby_block
- um trecho de código que não é executado até mais tarde. Algo parecido com isto:
remote_file "/tmp/foo" do
puts "in remote_file"
# this syntax isn't valid...
source do
node.default['test']['foo']
end
end
Felizmente, isso existe - é chamado Avaliação de Atributo Preguiçoso . Usando esse recurso, seu segundo exemplo ficaria assim:
ruby_block "block1" do
block do
node.default['test'] = {}
node.default['test']['foo'] = 'https://google.com'
puts "in block1"
end
action :create
end
remote_file "/tmp/foo" do
puts "in remote_file"
source lazy { node['test']['foo'] }
end
E a saída esperada desta receita?
- Nenhuma saída ao compilar o ruby_block
- "no remote_file" impresso durante a compilação do remote_file
- "no bloco1" impresso ao convergir o ruby_block
- Mensagem de registro do chef mostrando que o ruby_block foi convergido
- Mensagens de registro do chef mostrando o remote_file foram convergidas