lib/bolt/applicator.rb in bolt-1.42.0 vs lib/bolt/applicator.rb in bolt-1.43.0

- old
+ new

@@ -6,10 +6,11 @@ require 'logging' require 'open3' require 'bolt/error' require 'bolt/task' require 'bolt/apply_result' +require 'bolt/apply_target' require 'bolt/util/puppet_log_level' module Bolt class Applicator def initialize(inventory, executor, modulepath, plugin_dirs, pdb_client, hiera_config, max_compiles) @@ -127,10 +128,53 @@ raise(ApplyError, target.name) unless stat.success? JSON.parse(out) end + def future_compile(target, catalog_input) + trusted = Puppet::Context::TrustedInformation.new('local', target.name, {}) + catalog_input[:target] = { + name: target.name, + facts: @inventory.facts(target).merge('bolt' => true), + variables: @inventory.vars(target), + trusted: trusted.to_h + } + # rubocop:disable Style/GlobalVars + catalog_input[:future] = $future + # rubocop:enable Style/GlobalVars + + bolt_catalog_exe = File.join(libexec, 'bolt_catalog') + old_path = ENV['PATH'] + ENV['PATH'] = "#{RbConfig::CONFIG['bindir']}#{File::PATH_SEPARATOR}#{old_path}" + out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_input.to_json) + ENV['PATH'] = old_path + + # stderr may contain formatted logs from Puppet's logger or other errors. + # Print them in order, but handle them separately. Anything not a formatted log is assumed + # to be an error message. + logs = err.lines.map do |l| + begin + JSON.parse(l) + rescue StandardError + l + end + end + logs.each do |log| + if log.is_a?(String) + @logger.error(log.chomp) + else + log.map { |k, v| [k.to_sym, v] }.each do |level, msg| + bolt_level = Bolt::Util::PuppetLogLevel::MAPPING[level] + @logger.send(bolt_level, "#{target.name}: #{msg.chomp}") + end + end + end + + raise(ApplyError, target.name) unless stat.success? + JSON.parse(out) + end + def validate_hiera_config(hiera_config) if File.exist?(File.path(hiera_config)) data = File.open(File.path(hiera_config), "r:UTF-8") { |f| YAML.safe_load(f.read, [Symbol]) } if data.nil? return nil @@ -153,11 +197,10 @@ type1 = Puppet.lookup(:pal_script_compiler).type('Hash[String, Data]') Puppet::Pal.assert_type(type1, args[1], 'apply options') options = args[1].map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h end - # collect plan vars and merge them over target vars plan_vars = scope.to_hash(true, true) %w[trusted server_facts facts].each { |k| plan_vars.delete(k) } targets = @inventory.get_targets(args[0]) @@ -177,14 +220,36 @@ end def apply_ast(raw_ast, targets, options, plan_vars = {}) ast = Puppet::Pops::Serialization::ToDataConverter.convert(raw_ast, rich_data: true, symbol_to_string: true) + # rubocop:disable Style/GlobalVars + if $future + # Serialize as pcore for *Result* objects + plan_vars = Puppet::Pops::Serialization::ToDataConverter.convert(plan_vars, + rich_data: true, + symbol_as_string: true, + type_by_reference: true, + local_reference: false) + scope = { + code_ast: ast, + modulepath: @modulepath, + pdb_config: @pdb_client.config.to_hash, + hiera_config: @hiera_config, + plan_vars: plan_vars, + # This data isn't available on the target config hash + config: @inventory.config.transport_data_get + } + end + # rubocop:enable Style/GlobalVars + r = @executor.log_action('apply catalog', targets) do futures = targets.map do |target| Concurrent::Future.execute(executor: @pool) do @executor.with_node_logging("Compiling manifest block", [target]) do - compile(target, ast, plan_vars) + # rubocop:disable Style/GlobalVars + $future ? future_compile(target, scope) : compile(target, ast, plan_vars) + # rubocop:enable Style/GlobalVars end end end result_promises = targets.zip(futures).flat_map do |target, future|