bolt 0.21.2 → 0.21.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +1 -7
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +4 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +3 -0
- data/bolt-modules/boltlib/types/planresult.pp +1 -1
- data/lib/bolt/analytics.rb +0 -1
- data/lib/bolt/applicator.rb +81 -23
- data/lib/bolt/bolt_option_parser.rb +4 -0
- data/lib/bolt/catalog.rb +15 -14
- data/lib/bolt/cli.rb +13 -2
- data/lib/bolt/config.rb +29 -2
- data/lib/bolt/error.rb +1 -1
- data/lib/bolt/executor.rb +32 -9
- data/lib/bolt/pal.rb +8 -1
- data/lib/bolt/transport/ssh.rb +1 -0
- data/lib/bolt/transport/winrm.rb +1 -0
- data/lib/bolt/version.rb +1 -1
- data/libexec/bolt_catalog +8 -5
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfc1d47b6d45382d603a222c1aa4a5066a560e4439799afc00a15b44002497fb
|
4
|
+
data.tar.gz: 9e1c7c4c69d255092849484da518a6c9c02115917f8f5f3475ee8669b322bf70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29dd0f53e14ef2d7787e59ddf121f3a96a27c7b0810b3971a55a377c2e0f5d0996f78359e685459edbafea7a78e2e284b454027e22906edde2790bc9452ed23b
|
7
|
+
data.tar.gz: cb7268a4c9de0d2b8fd99649d112276c8542275b8f3ce7e134f7b1b2a041cb688537e13ce98a607753c597eec028ff1fb29c09ad1b18ead6aa291014e4dfb91d
|
@@ -17,14 +17,8 @@ Puppet::Functions.create_function(:puppetdb_fact) do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def puppetdb_fact(certnames)
|
20
|
-
unless Puppet[:tasks]
|
21
|
-
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
22
|
-
Puppet::Pops::Issues::TASK_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, operation: 'puppetdb_fact'
|
23
|
-
)
|
24
|
-
end
|
25
|
-
|
26
20
|
puppetdb_client = Puppet.lookup(:bolt_pdb_client) { nil }
|
27
|
-
unless puppetdb_client
|
21
|
+
unless puppetdb_client
|
28
22
|
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
29
23
|
Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('query facts from puppetdb')
|
30
24
|
)
|
@@ -16,7 +16,7 @@ Puppet::Functions.create_function(:puppetdb_query) do
|
|
16
16
|
|
17
17
|
def make_query(query)
|
18
18
|
puppetdb_client = Puppet.lookup(:bolt_pdb_client) { nil }
|
19
|
-
unless
|
19
|
+
unless puppetdb_client
|
20
20
|
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
21
21
|
Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('query facts from puppetdb')
|
22
22
|
)
|
@@ -13,6 +13,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
13
13
|
scope_param
|
14
14
|
param 'String', :plan_name
|
15
15
|
optional_param 'Hash', :named_args
|
16
|
+
return_type 'Boltlib::PlanResult'
|
16
17
|
end
|
17
18
|
|
18
19
|
def run_plan(scope, plan_name, named_args = {})
|
@@ -35,6 +36,9 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
35
36
|
executor.report_function_call('run_plan')
|
36
37
|
end
|
37
38
|
|
39
|
+
# Report bundled content, this should capture plans run from both CLI and Plans
|
40
|
+
executor.report_bundled_content('Plan', plan_name)
|
41
|
+
|
38
42
|
params = named_args.reject { |k, _| k.start_with?('_') }
|
39
43
|
|
40
44
|
loaders = closure_scope.compiler.loaders
|
@@ -86,6 +86,9 @@ Puppet::Functions.create_function(:run_task) do
|
|
86
86
|
executor.report_function_call('run_task')
|
87
87
|
end
|
88
88
|
|
89
|
+
# Report bundled content, this should capture tasks run from both CLI and Plans
|
90
|
+
executor.report_bundled_content('Task', task_name)
|
91
|
+
|
89
92
|
# Ensure that given targets are all Target instances
|
90
93
|
targets = inventory.get_targets(targets)
|
91
94
|
|
data/lib/bolt/analytics.rb
CHANGED
data/lib/bolt/applicator.rb
CHANGED
@@ -2,17 +2,72 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'open3'
|
5
|
+
require 'concurrent'
|
5
6
|
|
6
7
|
module Bolt
|
7
8
|
Task = Struct.new(:name, :implementations, :input_method)
|
8
9
|
|
9
10
|
class Applicator
|
10
|
-
def initialize(inventory, executor)
|
11
|
+
def initialize(inventory, executor, modulepath, pdb_config, hiera_config, max_compiles)
|
11
12
|
@inventory = inventory
|
12
13
|
@executor = executor
|
14
|
+
@modulepath = modulepath
|
15
|
+
@pdb_config = pdb_config
|
16
|
+
@hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
|
17
|
+
|
18
|
+
@pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
|
19
|
+
end
|
20
|
+
|
21
|
+
private def libexec
|
22
|
+
@libexec ||= File.join(Gem::Specification.find_by_name('bolt').gem_dir, 'libexec')
|
23
|
+
end
|
24
|
+
|
25
|
+
def catalog_apply_task
|
26
|
+
@catalog_apply_task ||= begin
|
27
|
+
path = File.join(libexec, 'apply_catalog.rb')
|
28
|
+
impl = { 'name' => 'apply_catalog.rb', 'path' => path, 'requirements' => [], 'supports_noop' => true }
|
29
|
+
Task.new('apply_catalog', [impl], 'stdin')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def compile(target, ast, plan_vars)
|
34
|
+
trusted = Puppet::Context::TrustedInformation.new('local', target.host, {})
|
35
|
+
|
36
|
+
catalog_input = {
|
37
|
+
code_ast: ast,
|
38
|
+
modulepath: @modulepath,
|
39
|
+
pdb_config: @pdb_config,
|
40
|
+
hiera_config: @hiera_config,
|
41
|
+
target: {
|
42
|
+
name: target.host,
|
43
|
+
facts: @inventory.facts(target),
|
44
|
+
variables: @inventory.vars(target).merge(plan_vars),
|
45
|
+
trusted: trusted.to_h
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
bolt_catalog_exe = File.join(libexec, 'bolt_catalog')
|
50
|
+
|
51
|
+
old_path = ENV['PATH']
|
52
|
+
ENV['PATH'] = "#{RbConfig::CONFIG['bindir']}#{File::PATH_SEPARATOR}#{old_path}"
|
53
|
+
out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_input.to_json)
|
54
|
+
ENV['PATH'] = old_path
|
55
|
+
|
56
|
+
raise ApplyError.new(target.to_s, err) unless stat.success?
|
57
|
+
JSON.parse(out)
|
13
58
|
end
|
14
59
|
|
15
|
-
def
|
60
|
+
def validate_hiera_config(hiera_config)
|
61
|
+
if File.exist?(File.path(hiera_config))
|
62
|
+
data = File.open(File.path(hiera_config), "r:UTF-8") { |f| YAML.safe_load(f.read) }
|
63
|
+
unless data['version'] == 5
|
64
|
+
raise ApplyError.new("All Targets", "Hiera v5 is required.")
|
65
|
+
end
|
66
|
+
hiera_config
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def apply(args, apply_body, scope)
|
16
71
|
raise(ArgumentError, 'apply requires a TargetSpec') if args.empty?
|
17
72
|
type0 = Puppet.lookup(:pal_script_compiler).type('TargetSpec')
|
18
73
|
Puppet::Pal.assert_type(type0, args[0], 'apply targets')
|
@@ -24,33 +79,36 @@ module Bolt
|
|
24
79
|
params = args[1]
|
25
80
|
end
|
26
81
|
|
82
|
+
# collect plan vars and merge them over target vars
|
83
|
+
plan_vars = scope.to_hash
|
84
|
+
%w[trusted server_facts facts].each { |k| plan_vars.delete(k) }
|
85
|
+
|
27
86
|
targets = @inventory.get_targets(args[0])
|
28
87
|
ast = Puppet::Pops::Serialization::ToDataConverter.convert(apply_body, rich_data: true, symbol_to_string: true)
|
29
|
-
|
30
|
-
catalog_input = {
|
31
|
-
code_ast: ast,
|
32
|
-
modulepath: [],
|
33
|
-
target: {
|
34
|
-
name: target.host,
|
35
|
-
facts: @inventory.facts(target),
|
36
|
-
variables: @inventory.vars(target)
|
37
|
-
}
|
38
|
-
}
|
88
|
+
notify = proc { |_| nil }
|
39
89
|
|
40
|
-
|
90
|
+
@executor.log_action('apply catalog', targets) do
|
91
|
+
futures = targets.map do |target|
|
92
|
+
Concurrent::Future.execute(executor: @pool) do
|
93
|
+
@executor.with_node_logging("Compiling manifest block", [target]) do
|
94
|
+
compile(target, ast, plan_vars)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
41
98
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
99
|
+
result_promises = targets.zip(futures).flat_map do |target, future|
|
100
|
+
@executor.queue_execute([target]) do |transport, batch|
|
101
|
+
@executor.with_node_logging("Applying manifest block", batch) do
|
102
|
+
arguments = params.clone
|
103
|
+
arguments['catalog'] = future.value
|
104
|
+
raise future.reason if future.rejected?
|
105
|
+
transport.batch_task(batch, catalog_apply_task, arguments, {}, ¬ify)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
46
109
|
|
47
|
-
|
48
|
-
impl = { 'name' => 'apply_catalog.rb', 'path' => path, 'requirements' => [], 'supports_noop' => true }
|
49
|
-
task = Task.new('apply_catalog', [impl], 'stdin')
|
50
|
-
params['catalog'] = catalog
|
51
|
-
@executor.run_task([target], task, params, '_description' => 'apply catalog')
|
110
|
+
@executor.await_results(result_promises)
|
52
111
|
end
|
53
|
-
ResultSet.new results.reduce([]) { |result, result_set| result + result_set.results }
|
54
112
|
end
|
55
113
|
end
|
56
114
|
end
|
@@ -183,6 +183,10 @@ Available options are:
|
|
183
183
|
'Maximum number of simultaneous connections (default: 100)') do |concurrency|
|
184
184
|
@options[:concurrency] = concurrency
|
185
185
|
end
|
186
|
+
define('--compile-concurrency CONCURRENCY', Integer,
|
187
|
+
'Maximum number of simultaneous manifest block compiles (default: number of cores)') do |concurrency|
|
188
|
+
@options[:'compile-concurrency'] = concurrency
|
189
|
+
end
|
186
190
|
define('--modulepath MODULES',
|
187
191
|
"List of directories containing modules, separated by '#{File::PATH_SEPARATOR}'") do |modulepath|
|
188
192
|
@options[:modulepath] = modulepath.split(File::PATH_SEPARATOR)
|
data/lib/bolt/catalog.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bolt/pal'
|
4
|
+
require 'bolt/puppetdb'
|
5
|
+
require 'bolt/util/on_access'
|
4
6
|
|
5
7
|
Bolt::PAL.load_puppet
|
6
8
|
|
@@ -53,13 +55,7 @@ end
|
|
53
55
|
|
54
56
|
module Bolt
|
55
57
|
class Catalog
|
56
|
-
def
|
57
|
-
Puppet::Pal.in_tmp_environment('bolt_apply', modulepath: ['~/bolt/modules/'], facts: @scope['facts']) do |pal|
|
58
|
-
yield pal
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def with_puppet_settings
|
58
|
+
def with_puppet_settings(hiera_config)
|
63
59
|
Dir.mktmpdir('bolt') do |dir|
|
64
60
|
cli = []
|
65
61
|
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
@@ -67,20 +63,19 @@ module Bolt
|
|
67
63
|
end
|
68
64
|
Puppet.settings.send(:clear_everything_for_tests)
|
69
65
|
Puppet.initialize_settings(cli)
|
66
|
+
Puppet.settings[:hiera_config] = hiera_config
|
70
67
|
# self.class.configure_logging
|
71
68
|
yield
|
72
69
|
end
|
73
70
|
end
|
74
71
|
|
75
|
-
def setup_node(node)
|
72
|
+
def setup_node(node, trusted)
|
76
73
|
facts = Puppet.lookup(:pal_facts)
|
77
74
|
node_facts = Puppet::Node::Facts.new(Puppet[:node_name_value], facts)
|
78
75
|
node.fact_merge(node_facts)
|
79
76
|
|
80
77
|
node.parameters = node.parameters.merge(Puppet.lookup(:pal_variables))
|
81
|
-
|
82
|
-
# TODO: setup trusted in params
|
83
|
-
# TODO: setup serverversion/clientversion in params
|
78
|
+
node.trusted_data = trusted
|
84
79
|
end
|
85
80
|
|
86
81
|
def compile_node(node)
|
@@ -101,7 +96,13 @@ module Bolt
|
|
101
96
|
def compile_catalog(request)
|
102
97
|
pal_main = request['code_ast'] || request['code_string']
|
103
98
|
target = request['target']
|
104
|
-
|
99
|
+
|
100
|
+
pdb_client = Bolt::Util::OnAccess.new do
|
101
|
+
pdb_config = Bolt::PuppetDB::Config.new(nil, request['pdb_config'])
|
102
|
+
Bolt::PuppetDB::Client.from_config(pdb_config)
|
103
|
+
end
|
104
|
+
|
105
|
+
with_puppet_settings(request['hiera_config']) do
|
105
106
|
Puppet[:code] = ''
|
106
107
|
Puppet[:node_name_value] = target['name']
|
107
108
|
Puppet::Pal.in_tmp_environment(
|
@@ -111,9 +112,9 @@ module Bolt
|
|
111
112
|
variables: target["variables"] || {}
|
112
113
|
) do |_pal|
|
113
114
|
node = Puppet.lookup(:pal_current_node)
|
114
|
-
setup_node(node)
|
115
|
+
setup_node(node, target["trusted"])
|
115
116
|
|
116
|
-
Puppet.override(pal_main: pal_main) do
|
117
|
+
Puppet.override(pal_main: pal_main, bolt_pdb_client: pdb_client) do
|
117
118
|
compile_node(node)
|
118
119
|
end
|
119
120
|
end
|
data/lib/bolt/cli.rb
CHANGED
@@ -262,7 +262,7 @@ module Bolt
|
|
262
262
|
params: params }
|
263
263
|
plan_context[:description] = options[:description] if options[:description]
|
264
264
|
|
265
|
-
executor = Bolt::Executor.new(config, @analytics, options[:noop])
|
265
|
+
executor = Bolt::Executor.new(config, @analytics, options[:noop], bundled_content: bundled_content)
|
266
266
|
executor.start_plan(plan_context)
|
267
267
|
result = pal.run_plan(options[:object], options[:task_options], executor, inventory, puppetdb_client)
|
268
268
|
|
@@ -271,7 +271,7 @@ module Bolt
|
|
271
271
|
outputter.print_plan_result(result)
|
272
272
|
code = result.ok? ? 0 : 1
|
273
273
|
else
|
274
|
-
executor = Bolt::Executor.new(config, @analytics, options[:noop])
|
274
|
+
executor = Bolt::Executor.new(config, @analytics, options[:noop], bundled_content: bundled_content)
|
275
275
|
targets = options[:targets]
|
276
276
|
|
277
277
|
results = nil
|
@@ -353,5 +353,16 @@ module Bolt
|
|
353
353
|
def outputter
|
354
354
|
@outputter ||= Bolt::Outputter.for_format(config[:format], config[:color], config[:trace])
|
355
355
|
end
|
356
|
+
|
357
|
+
def bundled_content
|
358
|
+
default_content = Bolt::PAL.new(Bolt::Config.new)
|
359
|
+
plans = default_content.list_plans.each_with_object([]) do |iter, col|
|
360
|
+
col << iter&.first
|
361
|
+
end
|
362
|
+
tasks = default_content.list_tasks.each_with_object([]) do |iter, col|
|
363
|
+
col << iter&.first
|
364
|
+
end
|
365
|
+
plans.concat tasks
|
366
|
+
end
|
356
367
|
end
|
357
368
|
end
|
data/lib/bolt/config.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'logging'
|
5
|
+
require 'concurrent'
|
5
6
|
require 'bolt/cli'
|
6
7
|
require 'bolt/transport/ssh'
|
7
8
|
require 'bolt/transport/winrm'
|
@@ -25,12 +26,14 @@ module Bolt
|
|
25
26
|
|
26
27
|
Config = Struct.new(
|
27
28
|
:concurrency,
|
29
|
+
:'compile-concurrency',
|
28
30
|
:format,
|
29
31
|
:trace,
|
30
32
|
:inventoryfile,
|
31
33
|
:log,
|
32
34
|
:modulepath,
|
33
35
|
:puppetdb,
|
36
|
+
:'hiera-config',
|
34
37
|
:color,
|
35
38
|
:transport,
|
36
39
|
:transports
|
@@ -38,6 +41,7 @@ module Bolt
|
|
38
41
|
|
39
42
|
DEFAULTS = {
|
40
43
|
concurrency: 100,
|
44
|
+
'compile-concurrency': Concurrent.processor_count,
|
41
45
|
transport: 'ssh',
|
42
46
|
format: 'human',
|
43
47
|
modulepath: [],
|
@@ -131,7 +135,7 @@ module Bolt
|
|
131
135
|
self[:modulepath] = data['modulepath'].split(File::PATH_SEPARATOR)
|
132
136
|
end
|
133
137
|
|
134
|
-
%w[inventoryfile concurrency format puppetdb color transport].each do |key|
|
138
|
+
%w[inventoryfile concurrency compile-concurrency format puppetdb hiera-config color transport].each do |key|
|
135
139
|
if data.key?(key)
|
136
140
|
self[key.to_sym] = data[key]
|
137
141
|
end
|
@@ -197,8 +201,12 @@ module Bolt
|
|
197
201
|
File.join(boltdir, 'inventory.yaml')
|
198
202
|
end
|
199
203
|
|
204
|
+
def default_hiera
|
205
|
+
File.join(boltdir, 'hiera.yaml')
|
206
|
+
end
|
207
|
+
|
200
208
|
def update_from_cli(options)
|
201
|
-
%i[concurrency transport format trace modulepath inventoryfile color].each do |key|
|
209
|
+
%i[concurrency compile-concurrency transport format trace modulepath inventoryfile color].each do |key|
|
202
210
|
self[key] = options[key] if options.key?(key)
|
203
211
|
end
|
204
212
|
|
@@ -236,6 +244,7 @@ module Bolt
|
|
236
244
|
# 'inventoryfile' cannot be included here or they will not be handled correctly.
|
237
245
|
def update_from_defaults
|
238
246
|
self[:modulepath] = default_modulepath
|
247
|
+
self[:'hiera-config'] = default_hiera
|
239
248
|
end
|
240
249
|
|
241
250
|
# The order in which config is processed is important
|
@@ -248,6 +257,7 @@ module Bolt
|
|
248
257
|
def load_file(path)
|
249
258
|
data = Bolt::Util.read_config_file(path, [default_config], 'config')
|
250
259
|
update_from_file(data) if data
|
260
|
+
validate_hiera_conf(data ? data['hiera-config'] : nil)
|
251
261
|
end
|
252
262
|
|
253
263
|
def update_from_inventory(data)
|
@@ -263,6 +273,10 @@ module Bolt
|
|
263
273
|
transports: self[:transports] }
|
264
274
|
end
|
265
275
|
|
276
|
+
def validate_hiera_conf(path)
|
277
|
+
Bolt::Util.read_config_file(path, [default_hiera], 'hiera-config')
|
278
|
+
end
|
279
|
+
|
266
280
|
def validate
|
267
281
|
self[:log].each_pair do |name, params|
|
268
282
|
if params.key?(:level) && !Bolt::Logger.valid_level?(params[:level])
|
@@ -274,6 +288,19 @@ module Bolt
|
|
274
288
|
end
|
275
289
|
end
|
276
290
|
|
291
|
+
unless self[:concurrency].is_a?(Integer) && self[:concurrency] > 0
|
292
|
+
raise Bolt::ValidationError, 'Concurrency must be a positive integer'
|
293
|
+
end
|
294
|
+
|
295
|
+
unless self[:'compile-concurrency'].is_a?(Integer) && self[:'compile-concurrency'] > 0
|
296
|
+
raise Bolt::ValidationError, 'Compile concurrency must be a positive integer'
|
297
|
+
end
|
298
|
+
|
299
|
+
compile_limit = 2 * Concurrent.processor_count
|
300
|
+
unless self[:'compile-concurrency'] < compile_limit
|
301
|
+
raise Bolt::ValidationError, "Compilation is CPU-intensive, set concurrency less than #{compile_limit}"
|
302
|
+
end
|
303
|
+
|
277
304
|
unless %w[human json].include? self[:format]
|
278
305
|
raise Bolt::ValidationError, "Unsupported format: '#{self[:format]}'"
|
279
306
|
end
|
data/lib/bolt/error.rb
CHANGED
data/lib/bolt/executor.rb
CHANGED
@@ -18,9 +18,13 @@ module Bolt
|
|
18
18
|
attr_reader :noop, :transports
|
19
19
|
attr_accessor :run_as, :plan_logging
|
20
20
|
|
21
|
-
def initialize(config = Bolt::Config.new,
|
21
|
+
def initialize(config = Bolt::Config.new,
|
22
|
+
analytics = Bolt::Analytics::NoopClient.new,
|
23
|
+
noop = nil,
|
24
|
+
bundled_content: nil)
|
22
25
|
@config = config
|
23
26
|
@analytics = analytics
|
27
|
+
@bundled_content = bundled_content
|
24
28
|
@logger = Logging.logger[self]
|
25
29
|
@plan_logging = false
|
26
30
|
|
@@ -46,15 +50,14 @@ module Bolt
|
|
46
50
|
impl.value
|
47
51
|
end
|
48
52
|
|
49
|
-
#
|
53
|
+
# Starts executing the given block on a list of nodes in parallel, one thread per "batch".
|
50
54
|
#
|
51
55
|
# This is the main driver of execution on a list of targets. It first
|
52
56
|
# groups targets by transport, then divides each group into batches as
|
53
|
-
# defined by the transport.
|
54
|
-
# transport,
|
55
|
-
|
56
|
-
|
57
|
-
promises = targets.group_by(&:protocol).flat_map do |protocol, protocol_targets|
|
57
|
+
# defined by the transport. Yields each batch, along with the corresponding
|
58
|
+
# transport, to the block in turn and returns an array of result promises.
|
59
|
+
def queue_execute(targets)
|
60
|
+
targets.group_by(&:protocol).flat_map do |protocol, protocol_targets|
|
58
61
|
transport = transport(protocol)
|
59
62
|
report_transport(transport, protocol_targets.count)
|
60
63
|
transport.batches(protocol_targets).flat_map do |batch|
|
@@ -90,9 +93,25 @@ module Bolt
|
|
90
93
|
batch_promises.values
|
91
94
|
end
|
92
95
|
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create a ResultSet from the results of all promises.
|
99
|
+
def await_results(promises)
|
93
100
|
ResultSet.new(promises.map(&:value))
|
94
101
|
end
|
95
102
|
|
103
|
+
# Execute the given block on a list of nodes in parallel, one thread per "batch".
|
104
|
+
#
|
105
|
+
# This is the main driver of execution on a list of targets. It first
|
106
|
+
# groups targets by transport, then divides each group into batches as
|
107
|
+
# defined by the transport. Each batch, along with the corresponding
|
108
|
+
# transport, is yielded to the block in turn and the results all collected
|
109
|
+
# into a single ResultSet.
|
110
|
+
def batch_execute(targets, &block)
|
111
|
+
promises = queue_execute(targets, &block)
|
112
|
+
await_results(promises)
|
113
|
+
end
|
114
|
+
|
96
115
|
def log_action(description, targets)
|
97
116
|
# When running a plan, info messages like starting a task are promoted to notice.
|
98
117
|
log_method = @plan_logging ? :notice : :info
|
@@ -115,7 +134,6 @@ module Bolt
|
|
115
134
|
|
116
135
|
results
|
117
136
|
end
|
118
|
-
private :log_action
|
119
137
|
|
120
138
|
def report_transport(transport, count)
|
121
139
|
name = transport.class.name.split('::').last.downcase
|
@@ -127,13 +145,18 @@ module Bolt
|
|
127
145
|
@analytics&.event('Plan', 'call_function', function)
|
128
146
|
end
|
129
147
|
|
148
|
+
def report_bundled_content(mode, name)
|
149
|
+
if @bundled_content&.include?(name)
|
150
|
+
@analytics&.event('Bundled Content', mode, name)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
130
154
|
def with_node_logging(description, batch)
|
131
155
|
@logger.info("#{description} on #{batch.map(&:uri)}")
|
132
156
|
result = yield
|
133
157
|
@logger.info(result.to_json)
|
134
158
|
result
|
135
159
|
end
|
136
|
-
private :with_node_logging
|
137
160
|
|
138
161
|
def run_command(targets, command, options = {}, &callback)
|
139
162
|
description = options.fetch('_description', "command '#{command}'")
|
data/lib/bolt/pal.rb
CHANGED
@@ -119,7 +119,14 @@ module Bolt
|
|
119
119
|
bolt_executor: executor,
|
120
120
|
bolt_inventory: inventory,
|
121
121
|
bolt_pdb_client: pdb_client,
|
122
|
-
apply_executor: Applicator.new(
|
122
|
+
apply_executor: Applicator.new(
|
123
|
+
inventory,
|
124
|
+
executor,
|
125
|
+
full_modulepath(@config[:modulepath]),
|
126
|
+
@config.puppetdb,
|
127
|
+
@config[:'hiera-config'],
|
128
|
+
@config[:'compile-concurrency']
|
129
|
+
)
|
123
130
|
}
|
124
131
|
Puppet.override(opts, &block)
|
125
132
|
end
|
data/lib/bolt/transport/ssh.rb
CHANGED
@@ -132,6 +132,7 @@ module Bolt
|
|
132
132
|
|
133
133
|
if ENVIRONMENT_METHODS.include?(input_method)
|
134
134
|
environment = arguments.inject({}) do |env, (param, val)|
|
135
|
+
val = val.to_json unless val.is_a?(String)
|
135
136
|
env.merge("PT_#{param}" => val)
|
136
137
|
end
|
137
138
|
execute_options[:environment] = environment
|
data/lib/bolt/transport/winrm.rb
CHANGED
@@ -112,6 +112,7 @@ catch
|
|
112
112
|
|
113
113
|
if ENVIRONMENT_METHODS.include?(input_method)
|
114
114
|
arguments.each do |(arg, val)|
|
115
|
+
val = val.to_json unless val.is_a?(String)
|
115
116
|
cmd = "[Environment]::SetEnvironmentVariable('PT_#{arg}', @'\n#{val}\n'@)"
|
116
117
|
result = conn.execute(cmd)
|
117
118
|
if result.exit_code != 0
|
data/lib/bolt/version.rb
CHANGED
data/libexec/bolt_catalog
CHANGED
@@ -7,12 +7,15 @@ require 'json'
|
|
7
7
|
|
8
8
|
# This accepts a catalog request on stdin:
|
9
9
|
# { "code_ast": "JSON serialized Puppet AST",
|
10
|
-
# "code_string": "String of code, ignored if AST is provided,
|
11
|
-
# "modulepath": "Array of directories to use as the modulepath for catalog compilation
|
10
|
+
# "code_string": "String of code, ignored if AST is provided",
|
11
|
+
# "modulepath": "Array of directories to use as the modulepath for catalog compilation",
|
12
|
+
# "pdb_config": "A hash of PDB client config options as supplied to Bolt",
|
13
|
+
# "hiera_config": "File path to hiera config file",
|
12
14
|
# "target": {
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
15
|
+
# "name": "the name of the node usually fqdn fro url",
|
16
|
+
# "facts": "Hash of facts to use for the node",
|
17
|
+
# "variables": "Hash of variables to use for compilation",
|
18
|
+
# "trusted": "Hash of trusted data for the node"
|
16
19
|
# }
|
17
20
|
# }
|
18
21
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.21.
|
4
|
+
version: 0.21.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.2
|
89
|
+
version: '0.2'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.2
|
96
|
+
version: '0.2'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: terminal-table
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,14 +198,14 @@ dependencies:
|
|
198
198
|
requirements:
|
199
199
|
- - "~>"
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: 1.0
|
201
|
+
version: '1.0'
|
202
202
|
type: :runtime
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
206
|
- - "~>"
|
207
207
|
- !ruby/object:Gem::Version
|
208
|
-
version: 1.0
|
208
|
+
version: '1.0'
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
210
|
name: bundler
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|