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|