lib/bolt/applicator.rb in bolt-0.21.4 vs lib/bolt/applicator.rb in bolt-0.21.5
- old
+ new
@@ -1,11 +1,14 @@
# frozen_string_literal: true
+require 'base64'
+require 'concurrent'
+require 'find'
require 'json'
require 'logging'
+require 'minitar'
require 'open3'
-require 'concurrent'
require 'bolt/util/puppet_log_level'
module Bolt
Task = Struct.new(:name, :implementations, :input_method)
@@ -17,16 +20,32 @@
@pdb_client = pdb_client
@hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
@pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
@logger = Logging.logger[self]
+ @plugin_tarball = Concurrent::Delay.new do
+ build_plugin_tarball do |mod|
+ search_dirs = []
+ search_dirs << mod.plugins if mod.plugins?
+ search_dirs << mod.files if mod.files?
+ search_dirs
+ end
+ end
end
private def libexec
@libexec ||= File.join(Gem::Specification.find_by_name('bolt').gem_dir, 'libexec')
end
+ def custom_facts_task
+ @custom_facts_task ||= begin
+ path = File.join(libexec, 'custom_facts.rb')
+ impl = { 'name' => 'custom_facts.rb', 'path' => path, 'requirements' => [], 'supports_noop' => true }
+ Task.new('custom_facts', [impl], 'stdin')
+ end
+ end
+
def catalog_apply_task
@catalog_apply_task ||= begin
path = File.join(libexec, 'apply_catalog.rb')
impl = { 'name' => 'apply_catalog.rb', 'path' => path, 'requirements' => [], 'supports_noop' => true }
Task.new('apply_catalog', [impl], 'stdin')
@@ -44,15 +63,15 @@
target: {
name: target.host,
facts: @inventory.facts(target),
variables: @inventory.vars(target).merge(plan_vars),
trusted: trusted.to_h
- }
+ },
+ inventory: @inventory.data_hash
}
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
@@ -142,10 +161,12 @@
def apply(args, apply_body, scope)
raise(ArgumentError, 'apply requires a TargetSpec') if args.empty?
type0 = Puppet.lookup(:pal_script_compiler).type('TargetSpec')
Puppet::Pal.assert_type(type0, args[0], 'apply targets')
+ @executor.report_function_call('apply')
+
options = {}
if args.count > 1
type1 = Puppet.lookup(:pal_script_compiler).type('Hash[String, Data]')
Puppet::Pal.assert_type(type1, args[1], 'apply options')
options = args[1]
@@ -169,11 +190,11 @@
end
result_promises = targets.zip(futures).flat_map do |target, future|
@executor.queue_execute([target]) do |transport, batch|
@executor.with_node_logging("Applying manifest block", batch) do
- arguments = { 'catalog' => future.value, '_noop' => options['_noop'] }
+ arguments = { 'catalog' => future.value, 'plugins' => plugins, '_noop' => options['_noop'] }
raise future.reason if future.rejected?
result = transport.batch_task(batch, catalog_apply_task, arguments, options, ¬ify)
result = provide_puppet_missing_errors(result)
identify_resource_failures(result)
end
@@ -185,8 +206,48 @@
if !r.ok && !options['_catch_errors']
raise Bolt::ApplyFailure, r
end
r
+ end
+
+ def plugins
+ @plugin_tarball.value ||
+ raise(Bolt::Error.new("Failed to pack module plugins: #{@plugin_tarball.reason}", 'bolt/plugin-error'))
+ end
+
+ def build_plugin_tarball
+ start_time = Time.now
+ sio = StringIO.new
+ output = Minitar::Output.new(Zlib::GzipWriter.new(sio))
+
+ Puppet.lookup(:current_environment).modules.each do |mod|
+ search_dirs = yield mod
+
+ parent = Pathname.new(mod.path).parent
+ files = Find.find(*search_dirs).select { |file| File.file?(file) }
+
+ files.each do |file|
+ tar_path = Pathname.new(file).relative_path_from(parent)
+ @logger.debug("Packing plugin #{file} to #{tar_path}")
+ stat = File.stat(file)
+ content = File.binread(file)
+ output.tar.add_file_simple(
+ tar_path.to_s,
+ data: content,
+ size: content.size,
+ mode: stat.mode & 0o777,
+ mtime: stat.mtime
+ )
+ end
+ end
+
+ duration = Time.now - start_time
+ @logger.debug("Packed plugins in #{duration * 1000} ms")
+
+ output.close
+ Base64.encode64(sio.string)
+ ensure
+ output&.close
end
end
end