class ChefCore::Actions::ConvergeTarget
Constants
- RUN_REPORTER_PATH
Public Instance Methods
chef_report_path()
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 139 def chef_report_path @chef_report_path ||= target_host.normalize_path(File.join(target_host.ws_cache_path, "cache", "run-report.json")) end
create_remote_config(dir)
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 72 def create_remote_config(dir) remote_config_path = File.join(dir, "workstation.rb") workstation_rb = <<~EOM local_mode true color false cache_path "#{target_host.ws_cache_path}" chef_repo_path "#{target_host.ws_cache_path}" require_relative "chef_run_reporter" reporter = ChefCore::ChefRunReporter.new report_handlers << reporter exception_handlers << reporter EOM # add the target host's log level value # (we don't set a location because we want output to # go in stdout for reporting back to chef-apply) unless config[:target_log_level].nil? workstation_rb << <<~EOM log_level :#{config[:target_log_level]} EOM end # Maybe add data collector endpoint. if !config[:data_collector_url].nil? && !config[:data_collector_token].nil? workstation_rb << <<~EOM data_collector.server_url "#{config[:data_collector_url]}" data_collector.token "#{config[:data_collector_token]}" data_collector.mode :solo data_collector.organization "Chef Workstation" EOM end begin config_file = Tempfile.new config_file.write(workstation_rb) config_file.close target_host.upload_file(config_file.path, remote_config_path) rescue RuntimeError raise ConfigUploadFailed.new ensure config_file.unlink end remote_config_path end
create_remote_handler(remote_dir)
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 118 def create_remote_handler(remote_dir) remote_handler_path = File.join(remote_dir, "chef_run_reporter.rb") target_host.upload_file(RUN_REPORTER_PATH, remote_handler_path) remote_handler_path rescue RuntimeError raise HandlerUploadFailed.new end
create_remote_policy(local_policy_path, remote_dir_path)
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 60 def create_remote_policy(local_policy_path, remote_dir_path) remote_policy_path = File.join(remote_dir_path, File.basename(local_policy_path)) notify(:creating_remote_policy) begin target_host.upload_file(local_policy_path, remote_policy_path) rescue RuntimeError => e ChefCore::Log.error(e) raise PolicyUploadFailed.new end remote_policy_path end
handle_ccr_error()
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 143 def handle_ccr_error require "chef_core/actions/converge_target/ccr_failure_mapper" mapper_opts = {} content = target_host.fetch_file_contents(chef_report_path) if content.nil? report = {} mapper_opts[:failed_report_path] = chef_report_path ChefCore::Log.error("Could not read remote report at #{chef_report_path}") else # We need to delete the stacktrace after copying it over. Otherwise if we get a # remote failure that does not write a chef stacktrace its possible to get an old # stale stacktrace. target_host.del_file(chef_report_path) report = JSON.parse(content) ChefCore::Log.error("Remote chef-client error follows:") ChefCore::Log.error(report["exception"]) end mapper = ConvergeTarget::CCRFailureMapper.new(report["exception"], mapper_opts) mapper.raise_mapped_exception! end
perform_action()
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 29 def perform_action local_policy_path = config.delete :local_policy_path remote_tmp = target_host.temp_dir remote_dir_path = target_host.normalize_path(remote_tmp) # Ensure the directory is owned by the connecting user, # otherwise we won't be able to put things into it over scp as that user. remote_policy_path = create_remote_policy(local_policy_path, remote_dir_path) remote_config_path = create_remote_config(remote_dir_path) create_remote_handler(remote_dir_path) upload_trusted_certs(remote_dir_path) notify(:running_chef) cmd_str = run_chef_cmd(remote_dir_path, File.basename(remote_config_path), File.basename(remote_policy_path)) c = target_host.run_command(cmd_str) target_host.del_dir(remote_dir_path) if c.exit_status == 0 ChefCore::Log.info(c.stdout) notify(:success) elsif c.exit_status == 35 notify(:reboot) else notify(:converge_error) ChefCore::Log.error("Error running command [#{cmd_str}]") ChefCore::Log.error("stdout: #{c.stdout}") ChefCore::Log.error("stderr: #{c.stderr}") handle_ccr_error end end
run_chef_cmd(working_dir, config_file, policy)
click to toggle source
TODO - move into target_host as 'get_ccr_command_string' Chef will try 'downloading' the policy from the internet unless we pass it a valid, local file in the working directory. By pointing it at a local file it will just copy it instead of trying to download it.
Chef 13 on Linux requires full path specifiers for –config and –recipe-url while on Chef 13 and 14 on Windows must use relative specifiers to prevent URI from causing an error (github.com/chef/chef/pull/7223/files).
# File lib/chef_core/actions/converge_target.rb, line 174 def run_chef_cmd(working_dir, config_file, policy) case target_host.base_os when :windows "Set-Location -Path #{working_dir}; " + # We must 'wait' for chef-client to finish before changing directories and Out-Null does that "chef-client -z --config #{File.join(working_dir, config_file)} --recipe-url #{File.join(working_dir, policy)} | Out-Null; " + # We have to leave working dir so we don't hold a lock on it, which allows us to delete this tempdir later "Set-Location C:/; " + "exit $LASTEXITCODE" else # cd is shell a builtin, so we'll invoke bash. This also means all commands are executed # with sudo (as long as we are hardcoding our sudo use) "bash -c 'cd #{working_dir}; chef-client -z --config #{File.join(working_dir, config_file)} --recipe-url #{File.join(working_dir, policy)}'" end end
upload_trusted_certs(dir)
click to toggle source
# File lib/chef_core/actions/converge_target.rb, line 126 def upload_trusted_certs(dir) local_tcd = ChefConfig::PathHelper.escape_glob_dir(config[:trusted_certs_dir]) certs = Dir.glob(File.join(local_tcd, "*.{crt,pem}")) return if certs.empty? notify(:uploading_trusted_certs) remote_tcd = "#{dir}/trusted_certs" target_host.make_directory(remote_tcd) certs.each do |cert_file| target_host.upload_file(cert_file, "#{remote_tcd}/#{File.basename(cert_file)}") end end