使用 Chef.event_handler 时是否可以访问 run_status 对象?

Is it possible to access the run_status object when using Chef.event_handler?

我遇到了一些似乎无法找到解决方案的第 22 条军规。我可以成功地做到这一点:

#
# Cookbook:: core_unix_base_cmcb
# Recipe:: email_on_fail

email_hash = node.default['core_unix_base_cmcb']['email_hash']
email_hash['mailserver'] = node['postfix']['main']['relayhost']
email_hash['subject'] = "Subject: Chef-client run failed on #{email_hash['hostname']}"
email_hash['message'] = "A Chef-client run failed on #{email_hash['hostname']}."
email_hash['recipient'] = [ 'someone@somewhere.com' ]

Chef.event_handler do
  on :run_failed do
    SendEmail::Helper.new.send_email(email_hash)
  end
end
require 'net/smtp'

module SendEmail
  class Helper
    def send_email(email_hash)
      msg = "From: #{email_hash[:sender]} < #{email_hash[:sender]}@#{email_hash[:hostname]}\n"
      msg << "To: #{email_hash[:recipient].join('; ')}\n"
      msg << "#{email_hash[:subject]}\n"
      msg << "Date: #{Time.now.rfc2822}\n\n"
      msg << "#{email_hash[:message]}\n"
      sender = 'chef-client-noreply@somewhere.com'
      Net::SMTP.start(email_hash[:mailserver], 25) do |smtp|
        smtp.send_message msg, sender, email_hash[:recipient]
      end
    end
  end
end

但是 - 我需要包含主厨客户的消息 run_status。 如果你加上

msg << "#{run_status.formatted_exception}\n"
msg << Array(backtrace).join('\n')

对于上面的例子,run_status没有定义。

我能找到的唯一示例是使用报告界面的自定义处理程序和 chef_handler 资源声明。所以我尝试了这个(来自我发现的一个例子):

chef_handler 'SendEmailOnFail::SendEmail' do # Full class name
  # relative path to your handler
  source ::File.expand_path('../../files/default/handlers/email_on_fail_helper.rb', __FILE__)
  # source 'email_on_fail_helper.rb'
  arguments email_hash  # Hash or Array to pass to handler constructor
end
require 'net/smtp'

module SendEmailOnFail
  class SendEmail < Chef::Handler
    def report(email_hash)
      if run_status.failed?
        msg = "From: #{email_hash[:sender]} < #{email_hash[:sender]}@#{email_hash[:hostname]}\n"
        msg << "To: #{email_hash[:recipient].join('; ')}\n"
        msg << "#{email_hash[:subject]}\n"
        msg << "Date: #{Time.now.rfc2822}\n\n"
        msg << "#{email_hash[:message]}\n"
        msg << "#{run_status.formatted_exception}\n"
        msg << Array(backtrace).join('\n')
        sender = 'chef-client-noreply@somewhere.com'
        Net::SMTP.start(email_hash[:mailserver], 25) do |smtp|
          smtp.send_message msg, sender, email_hash[:recipient]
        end
      end
    end
  end
end

当您使用该代码执行 chef-client 运行 时,它会在参数上出错(收到 1,预期 0)。 我在网上绝对没有发现 def 报告有任何参数的例子,所以我认为这就是问题所在。我们的组织需要这些参数,因为邮件服务器并不总是相同的,收件人也不总是相同的。

那么我如何才能在电子邮件消息的正文中获取有关 chef-client 运行 失败的信息,并将参数传递给库(或自定义处理程序)? 提前致谢。

解决方法是将 email_hash 设置为属性,报表处理程序可以使用节点方法访问节点对象,或者您可以使用 run_status.node['email_hash'][xxx] 而不是 email_hash[xxx]

处理程序中 run_status 对象的文档是 here

要进行更详细的交流,请随时加入 Chef 的 slack 以获得社区帮助(那里也有 Chef 的开发人员,他们对内部信息有很大帮助):https://community-slack.chef.io/

run_status 仅适用于 report 界面,如 documentation 中所述。

The run_status object is initialized by Chef Infra Client before the report interface is run for any handler.

不过...

So how can I get the information of what failed in a chef-client run in the body of the E-mail message, AND have parameters passed to the library (or custom handler)?

可以event_handlerrun_failed 块中获取异常详细信息。其中一些方法是:messagebacktracefull_message

:run_failedhere.

有变量的参考

例如,在我的 食谱 中,我将 message 添加到我的 email_hash。然后将其传递给发送电子邮件的辅助方法。

# Adding this for completeness, the required change is in "Chef.event_handler" block
email_hash = Hash.new
email_hash['node_name'] = Chef.run_context.node.name
email_hash['subject'] = "Chef run failed on #{email_hash['node_name']}"
email_hash['sender'] = 'admin@example.io'
email_hash['recipient'] = 'user@example.io'

# This is where we can access details of "exception"
Chef.event_handler do
  on :run_failed do |exception|
    email_hash['error_msg'] = exception.message
    SendEmail::Helper.new.send_email(email_hash)
  end
end

再次添加我的 SendEmail 助手 以确保完整性:

require 'net/smtp'

module SendEmail
  class Helper

    def send_email(email_hash)
      message = "From: #{email_hash['sender']}\n"
      message << "To: #{email_hash['recipient']}\n"
      message << "Subject: #{email_hash['subject']}\n"
      message << "Date: #{Time.now.rfc2822}\n\n"
      message << "Chef run failed on #{email_hash['node_name']}\n"
      message << "#{email_hash['error_msg']}\n"
      Net::SMTP.start('localhost', 25) do |smtp|
        smtp.send_message message, email_hash['sender'], email_hash['recipient']
      end
    end

  end
end

谢谢两位的回复。在发布我的问题后继续搜索互联网后,我终于 运行 找到了一个我可以使用的金块。 https://github.com/chef/chef/issues/7101

这个例子让我很幸运:

on :run_failed do |exception, run_status|

我真的不明白它是如何工作的,或者它在哪里记录,但它与您正在做的事情本质上是一样的,seshadri_c,并且工作得很好。我可以访问撰写邮件所需的内容,例如

run_status.run_context.cookbook_collection