如何终止/结束Chef运行?

57
在某些情况下,我需要以非零状态码终止/中止 Chef 运行,然后将该状态码传播回我们的部署链,并最终传播到 Jenkins,导致一个大而红的球。最好的方法是什么?
5个回答

118
针对未来可能不熟悉Chef的读者,本问题的答案解释了Chef run如何“收敛”节点或使其符合运行中声明的策略。这也被称为“收敛”。该过程分为两个阶段:“编译”和“执行”。编译阶段是当Chef评估(“编译”)配方的Ruby代码时,查找要添加到资源集合中的资源。完成后,它会“执行”每个资源的操作以将其置于所需状态。运行系统命令等。
Erik Hollensbe在2013年写了一篇非常棒的关于此如何工作的详细说明
现在,进入答案:
有几种方法可以结束Chef run或退出Chef recipe,具体取决于您想要如何进行,因为Chef recipes是Ruby代码。
如果您的目标是基于某个条件停止处理recipe,但继续运行其余部分,则使用return Ruby关键字。例如:
file '/tmp/ponies' do
  action :create
end

return if platform?('windows')

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

我们假设如果系统是Windows,则没有包管理器可以安装bunnies-and-flowers软件包,因此我们返回原处。
如果您希望完全中止Chef运行
简而言之:使用raise。在出现错误情况时,中止Chef运行是最佳实践。
话虽如此,如果在运行过程中遇到未处理的异常,chef-client将退出运行。例如,如果模板资源找不到其源文件,或者运行chef-client的用户没有权限执行诸如创建目录之类的操作。这就是为什么使用raise也可以结束运行的原因。
放置raise的位置很重要。如果您将其用于ruby_block资源中,则仅在收敛阶段的执行阶段中引发。如果您将其用于资源外部,例如上面的return示例,则会在编译阶段发生。
file '/tmp/ponies' do
  action :create
end

raise if platform?('windows')

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

也许我们在Windows上拥有一个软件包管理器,并且我们希望安装此软件包。如果发生错误,Chef将致命退出并给出堆栈跟踪。

过去几年中,另一种方法是使用Chef :: Application.fatal! - 就像我在这个答案中写的那样。时代已经改变,这是不推荐的。不要再这样做。如果你正在这样做,请切换到raise,如上所述,如果你的需求更复杂,请编写自己的异常处理程序(见下文)。

更优雅的错误处理

由于食谱是Ruby,因此您还可以使用begin..rescue块优雅地处理错误条件。

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会在Chef服务器上发出一个数据包的HTTP请求,如果服务器有问题(如404未找到、403未授权等),它将返回Net::HTTPServerException。我们可以尝试重试或进行其他处理,然后退回到raise

报告错误

如果您从命令行运行Chef,则简单退出并抛出堆栈跟踪即可。但是,如果您在几台甚至数十台或数百台机器上作为守护程序或cron运行它时,当出现问题时,这不是保持理智的好方法。

进入Chef的报告/异常处理功能。您可以为Chef运行使用处理程序。所有报告处理程序都在Chef运行结束时运行。异常处理程序在中止的Chef运行结束时运行。运行的状态已被跟踪,并且可以在处理程序中进行检查,因此您可以编写一个处理成功/完成或失败/中止的处理程序。

documentation 告诉你如何编写一个。它还包括可用的 open source handlers 列表,您可以用于各种服务,包括:

  • SMTP邮件
  • IRC
  • 石墨
  • HipChat

以及许多其他的。


3
太棒了!非常有帮助。我在各种Chef资源中寻找过这个答案,但没有找到。如果我找到了,这个问题就不会存在了。最近,我决定当我搜索一个问题的答案,无论是在Stackoverflow还是从预期的资源中都没有轻松找到时,一旦我得到了答案,我就会组织一个Stackoverflow问题和答案对来记录我所学到的知识。 - Jordan Dea-Mattson
1
我从未能够让 rescue Net::HTTPServerException 正常工作。它无法捕获异常。 - Zabba
2
喜欢西班牙审判的评论 :-) - Mamun
所以这就是为什么它被称为“收敛”! - wisbucky
1
我在Chef::Application.fatal!方法上添加了删除线。这种方法绝对不能被Chef用户使用,因为它是一个内部API,最终会导致错误。例如,请参见:https://github.com/chefspec/chefspec/issues/489#issuecomment-53592637 - lamont
我已经更新了答案,删除了 Chef::Application.fatal! 的方法 :). 谢谢,Lamont! - jtimberman

9

推荐中止或编辑 Chef 运行的方法是引发异常。以下是一个示例:

ruby_block "some tricky operation" do
  block do
    OperationFoo
    raise "Operation Foo Failed" if some_condition
  end
end

2
Chef::Application.fatal!应该能够满足您的需求。这是我们代码库中的一个示例,可能会有所帮助。
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

1
作为过去8年中的核心Chef开发者,请勿在食谱或菜谱代码中使用Chef::Application.fatal!。请参见:https://github.com/chefspec/chefspec/issues/489#issuecomment-53592637我们还经常遇到由于直接调用“fatal!”而导致的异常处理报告问题。我们无法接受这些问题作为错误,并且不会修复这种方法。规则很快将被添加到foodcritic以警告其使用。您可以将其视为正式的公司建议。 - lamont
@lamont 除了使用 raise 之外,还有其他的方法可以退出 recipe 并告诉 post handler recipe 失败了吗?我不想使用 raise,因为 raise 会显示整个堆栈跟踪,包括源代码。 - NewBee
我认为您需要使用自定义输出格式化程序来防止显示整个呈现的错误消息。 - lamont

-2

当您想让chef在某些操作后完成时,只需使用以下语句:

throw :end_client_run_early

它将不会出现任何错误而退出。


-5

如果要在 chef-solo 运行期间进行异常退出,请尝试以下方法:

bash 'exit' do
    code 'killall -9 chef-solo'
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接