web-dev-qa-db-fra.com

Comment interrompre / terminer une course Chef?

Dans certaines conditions, je dois interrompre/terminer une exécution Chef avec un code d'état différent de zéro, qui se propagera ensuite à travers notre chaîne de déploiement et finalement à Jenkins, ce qui se traduira par une grosse et grosse boule rouge.

Quelle est la meilleure façon de procéder?

52
Jordan Dea-Mattson

Pour les lecteurs qui viendront à l'avenir à cette question et à une réponse qui ne connaissent peut-être pas Chef, une exécution Chef "fait converger" le nœud ou l'aligne sur la politique déclarée dans la ou les recettes qu'il exécute. Ceci est également appelé "convergence". Cela comporte deux phases, "compiler" et "exécuter". La phase de compilation est lorsque Chef évalue ("compile") les recettes Ruby code, à la recherche de ressources à ajouter à la collection de ressources. Une fois cela terminé, il "exécute" les actions pour chaque pour la mettre dans l'état souhaité. Les commandes système sont exécutées, etc.

Erik Hollensbe a écrit une excellente explication de la façon dont cela fonctionne en 2013 .

Maintenant, pour la réponse:

Il existe plusieurs façons de mettre fin à une exécution Chef ou de quitter une recette Chef, selon la façon dont vous voulez vous y prendre, car les recettes Chef sont Ruby code.

Si votre objectif est d'arrêter le traitement d'une recette basée sur une condition, mais de poursuivre le reste de l'exécution, utilisez le mot clé return Ruby. Par exemple:

file '/tmp/ponies' do
  action :create
end

return if node['platform'] == 'windows'

package 'bunnies-and-flowers' do
  action :install
end

Nous supposons que si le système est Windows, il n'a pas de gestionnaire de paquets qui peut installer le paquet bunnies-and-flowers, donc nous revenons d'où nous venons.

Si vous souhaitez interrompre entièrement l'exécution de Chef

Tl; dr: utilisez raise. Il est recommandé d'interrompre une exécution Chef en cas d'erreur.

Cela dit, le chef-client quitte s'il rencontre une exception non gérée n'importe où dans la course. Par exemple, si une ressource de modèle ne trouve pas son fichier source ou si l'utilisateur exécutant chef-client n'a pas l'autorisation de faire quelque chose comme créer un répertoire. C'est pourquoi l'utilisation de raise fonctionne également pour mettre fin à une exécution.

L'endroit où vous mettez raise est important. Si vous l'utilisez dans un Ruby_block ressource, elle n'augmentera que pendant la phase d'exécution en convergence. Si vous l'utilisez en dehors d'une ressource comme l'exemple return ci-dessus, cela se produira pendant la phase de compilation.

file '/tmp/ponies' do
  action :create
end

raise if node['platform'] == 'windows'

package 'bunnies-and-flowers' do
  action :install
end

Peut-être avons-nous un gestionnaire de paquets sur Windows et nous voulons que ce paquet soit installé. L'augmentation entraînera la sortie fatale de Chef et donnera une trace de pile.

Au cours des années passées, une autre approche consistait à utiliser Chef::Application.fatal! - comme écrit par moi dans cette réponse. Les temps ont changé et c'est NON RECOMMANDÉ. Ne fais plus ça. Si vous le faites, passez à raise et comme mentionné, écrivez votre propre gestionnaire d'exceptions si vos besoins sont plus compliqués (voir ci-dessous).

Gestion des erreurs plus gracieuse

Comme les recettes sont Ruby, vous pouvez également gérer avec élégance les conditions d'erreur avec un begin..rescue bloquer.

begin
  dater = data_bag_item(:basket, "flowers")
rescue Net::HTTPServerException
  # maybe some retry code here?
  raise "Couldn't find flowers in the basket, need those to continue!"
end

data_bag_item fait une demande HTTP pour un sac de données sur le serveur Chef et renverra un Net::HTTPServerException en cas de problème du serveur (404 introuvable, 403 non autorisé, etc.). Nous pourrions éventuellement tenter de réessayer ou effectuer une autre manipulation, puis retomber sur raise.

Signalement des erreurs

Il suffit de quitter et de lancer une trace de pile si vous exécutez Chef à partir de la ligne de commande. Cependant, si vous l'exécutez dans cron ou en tant que démon sur plusieurs, voire des dizaines ou des centaines de machines, ce n'est pas un excellent moyen de rester sain d'esprit en cas de problème.

Entrez la fonction de gestionnaire de rapport/exception du chef . Vous pouvez utiliser un gestionnaire pour vos courses Chef. Tous les gestionnaires de rapports sont exécutés à la fin d'une exécution Chef. Les gestionnaires d'exceptions sont exécutés à la fin d'une exécution Chef abandonnée. L'état de l'exécution est suivi et peut être vérifié dans le gestionnaire, vous pouvez donc en écrire un qui gère les deux types d'exécution (réussi/terminé ou échoué/abandonné).

La documentation vous indique comment en écrire un. Il comprend également une liste de gestionnaires open source disponibles que vous pouvez utiliser pour une variété de services, notamment:

  • Courriel via SMTP
  • IRC
  • Graphite
  • HipChat

Et beaucoup plus.

108
jtimberman

La méthode recommandée pour abandonner ou modifier une exécution Chef consiste à déclencher une exception. Voici un exemple:

Ruby_block "some tricky operation" do
  block do
    OperationFoo
    raise "Operation Foo Failed" if some_condition
  end
end
7
Jordan Dea-Mattson

Chef :: Application.fatal! devrait faire ce que vous cherchez. Voici un exemple de notre base de code qui pourrait être utile.

cipher = case key.length
    when 16 then "AES-128-ECB"
    when 24 then "AES-192-ECB"
    when 32 then "AES-256-ECB"
else
    Chef::Application.fatal!("AES Key must be 16, 24, or 32 characters in length but key #{key} has length of #{key.length}")
end
3
John T Dyer