Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture Chef exceptions

I'm working on a Chef recipe right now and I need to update a data bag with some information depending on the result of a code. Basically I need to update a data bag with succeed or failed.

The code looks like this:

begin
     node[:fileDeploy].each do |f|
        if f[:deploy]
          cookbook_file "#{f[:subdirectory]}/#{f[:targetFilename]}" do
             owner users['tomcatUser']
             group users['tomcatGroup']
             mode "0755"
             cookbook node[:cookbookName]
             source "#{f[:sourceFilename]}"
          end
        end
     end
     # Update data bag: succeeded
rescue Chef::Exceptions::FileNotFound => e
     # Update data bag: failed
end

The problem is that even though there is a missing file, the rescue block is not excecuted and the data bag is not updated accordingly. So, when I run the command sudo chef-client on the server, it ends up with the exception Chef::Exceptions::FileNotFound but it is not being handled by the rescue block. does it make sense? Any help?

like image 449
Leonardo Borysiuk Avatar asked Oct 28 '25 08:10

Leonardo Borysiuk


1 Answers

Your rescue block doesn't catch the exception because the code raising the exception is not executed in the scope of the exception handler.

In your code, you declare a cookbook_file resource. The declaration goes fine and the resource is scheduled for execution during the convergence phase. Your rescue block could catch an exception that would occur during declaration of the resource, not when it is actually executed.

Please see About the chef-client Run to learn more about the two phases of a chef run, namely the generation of the resource collection and the later convergence.

Now for your desired result, you could check the condition that the source file exists during convergence and decide accordingly.

Generally, handling errors is rather hard in Chef. This is by design, as you generally should design your system that it is rather independent from other parts. So if you need a directory or file to be present, you ought to create that one explicitly using the appropriate resource. You can then use notifications to notify other resources to run a certain action if the current resource "changed" (whatever that means for the specific resource).

The code below tries to achieve something similar to what you apparently want. It still doesn't catch an exception during convergence but tries to not raise one in the first place but checks the required conditions and runs the appropriate resources.

node[:fileDeploy].each do |f|
  if f[:deploy]
    cookbook_file "#{f[:subdirectory]}/#{f[:targetFilename]}" do
      owner users['tomcatUser']
      group users['tomcatGroup']
      mode "0755"
      cookbook node[:cookbookName]
      source f[:sourceFilename]
      only_if{ Dir.exist?(File.base_name(f[:sourceFilename]) }
      notifies :run, "execute[success #{f[:sourceFilename]}]", :immediately
    end

    # This one gets notified (and run) when the cookbook_file is successful
    execute "success #{f[:sourceFilename]}" do
      action :nothing
      command "do whatever you like"
    end

    # This one runs only if the created file doesn't exist by now
    execute "error #{f[:subdirectory]}/#{f[:targetFilename]}" do
      action :run
      command "do whatever you like"
      creates "#{f[:subdirectory]}/#{f[:targetFilename]}"
    end
  end
end
like image 128
Holger Just Avatar answered Oct 30 '25 10:10

Holger Just



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!