Bonne question - les deux exemples fonctionnent comme je m'y attendrais, mais il n'est pas immédiatement évident pourquoi.
Comme l'a écrit StephenKing dans sa réponse, la première chose à comprendre est que les recettes sont compilées (pour produire un ensemble de ressources), puis les ressources sont convergées (pour effectuer des modifications sur votre système). Ces deux phases sont souvent entremêlées - certaines de vos ressources peuvent être convergées avant que Chef n'ait fini de compiler toutes vos recettes. Erik Hollensbe couvre cela en détail dans son article "The Chef Resource Run Queue".
Voici à nouveau votre premier exemple:
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
Voici les étapes que Chef suivra pour traiter cet exemple.
- Tout d'abord, la déclaration de ruby_block est compilée, ce qui donne une ressource appelée
ruby_block[block1]
ajoutée à la collection de ressources. Le contenu du bloc (la première déclaration de puts
) ne s'exécute pas encore - il est enregistré pour s'exécuter lorsque cette ressource sera convergée.
- Ensuite, la déclaration de remote_file est compilée. Cela donne une ressource appelée
remote_file[/tmp/foo/]
ajoutée à la collection de ressources, avec une source de "https://yahoo.com". Au cours de la compilation de cette déclaration, la deuxième déclaration de puts
sera exécutée - cela a pour effet secondaire d'imprimer "in remote_file", mais cela n'affecte pas la ressource qui est placée dans la collection de ressources.
- N'ayant rien d'autre à compiler, Chef commence à converger les ressources dans la collection de ressources. Le premier est
ruby_block[block1]
, et Chef exécute le code ruby dans le bloc - en imprimant "in block1". Après avoir terminé d'exécuter le bloc, il enregistre un message pour dire que la ressource a été appelée.
- Enfin, Chef converge
remote_file[/tmp/foo]
. Encore une fois, il enregistre un message (ou deux) associé à cette activité.
Cela devrait produire la séquence de sortie suivante:
- Rien n'est imprimé lorsque le ruby_block est compilé.
- "in remote_file" sera imprimé pendant que le remote_file est compilé.
- "in block1" sera imprimé pendant que le ruby_block est convergé.
- Un message de journal Chef sera imprimé après que le ruby_block ait été convergé.
- D'autres messages de journal Chef seront imprimés pendant/après que le remote_file soit convergé.
Pour votre deuxième exemple:
ruby_block "block1" do
block do
node.default['test'] = {}
node.default['test']['foo'] ='https://google.com'
puts "in block1"
end
action :create
Comme pour le premier exemple, nous ne nous attendons pas à ce que quoi que ce soit soit imprimé pendant que le ruby_block est compilé - tout le "bloc" est sauvegardé, et son contenu ne s'exécutera pas tant que cette ressource ne sera pas convergée.
La première sortie que nous voyons est "in remote_file", car l'instruction puts
est exécutée lorsque Chef compile la ressource remote_file. À la ligne suivante, nous définissons le paramètre source
sur la valeur de node.default['test']['foo']
, qui est apparemment {}
. Ce n'est pas une valeur valide pour source
, donc l'exécution de Chef se termine à ce moment-là - avant que le code dans le ruby_block
ne soit jamais exécuté.
Par conséquent, la sortie attendue de cette recette est:
- Aucune sortie pendant la compilation du ruby_block
- "in remote_file" imprimé lors de la compilation du remote_file
- Une erreur due au paramètre
source
invalide
J'espère que cela vous aide à comprendre le comportement que vous observez, mais nous avons toujours un problème à résoudre.
Vous avez demandé "comment puis-je forcer l'exécution du ruby_block en premier?", mais votre commentaire à StephenKing suggère que ce n'est pas vraiment ce que vous voulez - si vous vouliez vraiment que ce bloc s'exécute en premier, vous pourriez le mettre directement dans votre code de recette. Alternativement, vous pourriez utiliser la méthode .run_action() pour forcer la ressource à être convergée dès qu'elle est compilée - mais vous dites qu'il y a encore d'autres ressources qui doivent converger avant que le ruby_block ne soit utile.
Comme nous l'avons vu ci-dessus, les ressources ne sont pas "exécutées", elles sont d'abord "compilées", puis "convergées". Avec cela à l'esprit, ce dont vous avez besoin est que la ressource remote_file
utilise certaines données qui ne sont pas connues lorsqu'elle est compilée, mais qui le seront lorsqu'elle sera convergée. En d'autres termes, quelque chose comme le paramètre "block" dans le ruby_block
- un morceau de code qui ne s'exécute pas immédiatement. Quelque chose comme ceci:
remote_file "/tmp/foo" do
puts "in remote_file"
# cette syntaxe n'est pas valide...
source do
node.default['test']['foo']
end
Heureusement, une telle chose existe - c'est ce qu'on appelle l'Évaluation Paresseuse d'Attribut. En utilisant cette fonctionnalité, votre deuxième exemple ressemblerait à ceci:
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'] }
Et la sortie attendue de cette recette?
- Aucune sortie pendant la compilation du ruby_block
- "in remote_file" imprimé lors de la compilation du remote_file
- "in block1" imprimé lors de la convergence du ruby_block
- Message de journal Chef montrant que le ruby_block a été convergé
- Messages de journal Chef montrant que le remote_file a été convergé