class Chef::Knife::EcErrorHandler
This class handles the errors that we might encounter on a backup or restore, it stors the errors inside a specific file inside the working directory.
Attributes
Public Class Methods
Creates a new instance of the EcErrorHandler
to start adding errors during a backup or restore.
# File lib/chef/knife/ec_error_handler.rb, line 28 def initialize(working_dir, process) @err_dir = "#{working_dir}/errors" FileUtils.mkdir_p(@err_dir) # Create an specific error file name depending # of where the process comes from. @err_file = if process == Chef::Knife::EcRestore File.join(@err_dir, "restore-#{Time.now.iso8601}.json") elsif process == Chef::Knife::EcBackup File.join(@err_dir, "backup-#{Time.now.iso8601}.json") else File.join(@err_dir, "other-#{Time.now.iso8601}.json") end # exit handler at_exit { display(@err_file) } end
Public Instance Methods
Add an exception to the error file.
For now we are writing all the errors to a single file, but in the future we would like to be able to generate a full path just as we do when we are backing up the Server
, just that putting the file inside `{work_dir}/errors/{path}`
Example: A failed user
> {work_dir}/errors/users/afiune.json¶ ↑
A failed cookbook
> {work_dir}/errors/cookbooks/burger.json¶ ↑
A failed environment
> {work_dir}/errors/environment/dev.json¶ ↑
The advantages of this schema is the ability to retry the backup or restore and pick up where we left.
# File lib/chef/knife/ec_error_handler.rb, line 63 def add(ex) msg = { timestamp: Time.now, message: ex.message, backtrace: ex.backtrace, exception: ex.class } if ex.respond_to?(:chef_rest_request=) && ex.chef_rest_request msg.merge!( req_path: ex.chef_rest_request.path, req_method: ex.chef_rest_request.method ) elsif ex.instance_of?(Chef::ChefFS::FileSystem::NotFoundError) msg.merge!( entry: ex.entry, cause: ex.cause, reason: ex.reason ) elsif ex.instance_of?(Chef::ChefFS::FileSystem::OperationFailedError) msg.merge!( entry: ex.entry, operation: ex.operation ) end lock_file(@err_file, 'a') do |f| f.write(Chef::JSONCompat.to_json_pretty(msg)) end end
# File lib/chef/knife/ec_error_handler.rb, line 111 def display(file_name = @err_file) # Print summary report only if error file exist return unless File.exist?(file_name) puts "\nError Summary Report" lock_file(file_name, 'r') do |f| f.each_line do |line| puts line end end puts "\nError(s) Summary file located at: '#{file_name}'" end
Why lock the error file?
Well because ec-backup has a concurrency options that will allow you to backup and restore things in parallel, therefor we need to ensure that only one process is writing to the error file.
# File lib/chef/knife/ec_error_handler.rb, line 100 def lock_file(file_name, mode) File.open(file_name, mode) do |f| begin f.flock ::File::LOCK_EX yield f ensure f.flock ::File::LOCK_UN end end end