bolt 3.3.0 → 3.7.0
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/Puppetfile +5 -5
- data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +24 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +66 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +20 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +19 -2
- data/bolt-modules/boltlib/types/planresult.pp +1 -0
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +20 -2
- data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
- data/guides/targets.txt +31 -0
- data/lib/bolt/analytics.rb +4 -8
- data/lib/bolt/bolt_option_parser.rb +35 -17
- data/lib/bolt/cli.rb +109 -28
- data/lib/bolt/config.rb +11 -7
- data/lib/bolt/config/options.rb +41 -9
- data/lib/bolt/config/transport/lxd.rb +3 -1
- data/lib/bolt/config/transport/options.rb +7 -0
- data/lib/bolt/config/transport/podman.rb +33 -0
- data/lib/bolt/container_result.rb +105 -0
- data/lib/bolt/error.rb +15 -0
- data/lib/bolt/executor.rb +27 -15
- data/lib/bolt/inventory.rb +5 -4
- data/lib/bolt/inventory/inventory.rb +3 -2
- data/lib/bolt/inventory/options.rb +9 -0
- data/lib/bolt/inventory/target.rb +16 -0
- data/lib/bolt/node/output.rb +14 -4
- data/lib/bolt/outputter/human.rb +243 -84
- data/lib/bolt/outputter/json.rb +6 -4
- data/lib/bolt/outputter/logger.rb +17 -0
- data/lib/bolt/pal.rb +22 -2
- data/lib/bolt/pal/yaml_plan/step.rb +4 -2
- data/lib/bolt/pal/yaml_plan/step/command.rb +8 -0
- data/lib/bolt/pal/yaml_plan/step/script.rb +4 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +2 -2
- data/lib/bolt/plan_creator.rb +2 -2
- data/lib/bolt/plugin.rb +13 -11
- data/lib/bolt/puppetdb/client.rb +54 -0
- data/lib/bolt/result.rb +5 -14
- data/lib/bolt/shell/bash.rb +33 -22
- data/lib/bolt/shell/powershell.rb +6 -8
- data/lib/bolt/transport/docker.rb +1 -1
- data/lib/bolt/transport/docker/connection.rb +21 -32
- data/lib/bolt/transport/lxd/connection.rb +5 -5
- data/lib/bolt/transport/orch.rb +13 -5
- data/lib/bolt/transport/podman.rb +19 -0
- data/lib/bolt/transport/podman/connection.rb +98 -0
- data/lib/bolt/util.rb +42 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +3 -0
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +8 -1
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +8 -1
- data/lib/bolt_spec/plans/mock_executor.rb +91 -11
- data/modules/puppet_connect/plans/test_input_data.pp +22 -0
- metadata +11 -2
data/lib/bolt/inventory.rb
CHANGED
@@ -86,6 +86,7 @@ module Bolt
|
|
86
86
|
if config.default_inventoryfile.exist?
|
87
87
|
logger.debug("Loaded inventory from #{config.default_inventoryfile}")
|
88
88
|
else
|
89
|
+
source = nil
|
89
90
|
logger.debug("Tried to load inventory from #{config.default_inventoryfile}, but the file does not exist")
|
90
91
|
end
|
91
92
|
end
|
@@ -100,17 +101,17 @@ module Bolt
|
|
100
101
|
validator.warnings.each { |warning| Bolt::Logger.warn(warning[:id], warning[:msg]) }
|
101
102
|
end
|
102
103
|
|
103
|
-
inventory = create_version(data, config.transport, config.transports, plugins)
|
104
|
+
inventory = create_version(data, config.transport, config.transports, plugins, source)
|
104
105
|
inventory.validate
|
105
106
|
inventory
|
106
107
|
end
|
107
108
|
|
108
|
-
def self.create_version(data, transport, transports, plugins)
|
109
|
+
def self.create_version(data, transport, transports, plugins, source = nil)
|
109
110
|
version = (data || {}).delete('version') { 2 }
|
110
111
|
|
111
112
|
case version
|
112
113
|
when 2
|
113
|
-
Bolt::Inventory::Inventory.new(data, transport, transports, plugins)
|
114
|
+
Bolt::Inventory::Inventory.new(data, transport, transports, plugins, source)
|
114
115
|
else
|
115
116
|
raise ValidationError.new("Unsupported version #{version} specified in inventory", nil)
|
116
117
|
end
|
@@ -120,7 +121,7 @@ module Bolt
|
|
120
121
|
config = Bolt::Config.default
|
121
122
|
plugins = Bolt::Plugin.setup(config, nil)
|
122
123
|
|
123
|
-
create_version({}, config.transport, config.transports, plugins)
|
124
|
+
create_version({}, config.transport, config.transports, plugins, nil)
|
124
125
|
end
|
125
126
|
end
|
126
127
|
end
|
@@ -6,7 +6,7 @@ require 'bolt/inventory/target'
|
|
6
6
|
module Bolt
|
7
7
|
class Inventory
|
8
8
|
class Inventory
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :config, :plugins, :source, :targets, :transport
|
10
10
|
|
11
11
|
class WildcardError < Bolt::Error
|
12
12
|
def initialize(target)
|
@@ -15,7 +15,7 @@ module Bolt
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# TODO: Pass transport config instead of config object
|
18
|
-
def initialize(data, transport, transports, plugins)
|
18
|
+
def initialize(data, transport, transports, plugins, source = nil)
|
19
19
|
@logger = Bolt::Logger.logger(self)
|
20
20
|
@data = data || {}
|
21
21
|
@transport = transport
|
@@ -24,6 +24,7 @@ module Bolt
|
|
24
24
|
@groups = Group.new(@data, plugins, all_group: true)
|
25
25
|
@group_lookup = {}
|
26
26
|
@targets = {}
|
27
|
+
@source = source
|
27
28
|
|
28
29
|
@groups.resolve_string_targets(@groups.target_aliases, @groups.all_targets)
|
29
30
|
|
@@ -11,8 +11,10 @@ module Bolt
|
|
11
11
|
facts
|
12
12
|
features
|
13
13
|
groups
|
14
|
+
plugin_hooks
|
14
15
|
targets
|
15
16
|
vars
|
17
|
+
version
|
16
18
|
].freeze
|
17
19
|
|
18
20
|
# Definitions used to validate the data.
|
@@ -123,6 +125,13 @@ module Bolt
|
|
123
125
|
description: "A map of variables for the group or target.",
|
124
126
|
type: Hash,
|
125
127
|
_plugin: true
|
128
|
+
},
|
129
|
+
"version" => {
|
130
|
+
description: "The version of the inventory file.",
|
131
|
+
type: Integer,
|
132
|
+
_plugin: false,
|
133
|
+
_example: 2,
|
134
|
+
_default: 2
|
126
135
|
}
|
127
136
|
}.freeze
|
128
137
|
end
|
@@ -92,6 +92,7 @@ module Bolt
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def add_facts(new_facts = {})
|
95
|
+
validate_fact_names(new_facts)
|
95
96
|
@facts = Bolt::Util.deep_merge(@facts, new_facts)
|
96
97
|
end
|
97
98
|
|
@@ -153,9 +154,24 @@ module Bolt
|
|
153
154
|
raise Bolt::UnknownTransportError.new(transport, uri)
|
154
155
|
end
|
155
156
|
|
157
|
+
validate_fact_names(facts)
|
158
|
+
|
156
159
|
transport_config
|
157
160
|
end
|
158
161
|
|
162
|
+
# Validate fact names and issue a deprecation warning if any fact names have a dot.
|
163
|
+
#
|
164
|
+
private def validate_fact_names(facts)
|
165
|
+
if (dotted = facts.keys.select { |name| name.include?('.') }).any?
|
166
|
+
Bolt::Logger.deprecate(
|
167
|
+
'dotted_fact_name',
|
168
|
+
"Target '#{safe_name}' includes dotted fact names: '#{dotted.join("', '")}'. Dotted fact "\
|
169
|
+
"names are deprecated and Bolt does not automatically convert facts with dotted names to "\
|
170
|
+
"structured facts. For more information, see https://pup.pt/bolt-dotted-facts"
|
171
|
+
)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
159
175
|
def host
|
160
176
|
@uri_obj.hostname || transport_config['host']
|
161
177
|
end
|
data/lib/bolt/node/output.rb
CHANGED
@@ -6,13 +6,23 @@ require 'bolt/result'
|
|
6
6
|
module Bolt
|
7
7
|
class Node
|
8
8
|
class Output
|
9
|
-
attr_reader :stdout, :
|
9
|
+
attr_reader :stderr, :stdout, :merged_output
|
10
10
|
attr_accessor :exit_code
|
11
11
|
|
12
12
|
def initialize
|
13
|
-
@stdout
|
14
|
-
@stderr
|
15
|
-
@
|
13
|
+
@stdout = StringIO.new
|
14
|
+
@stderr = StringIO.new
|
15
|
+
@merged_output = StringIO.new
|
16
|
+
@exit_code = 'unknown'
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
{
|
21
|
+
'stdout' => @stdout.string,
|
22
|
+
'stderr' => @stderr.string,
|
23
|
+
'merged_output' => @merged_output.string,
|
24
|
+
'exit_code' => @exit_code
|
25
|
+
}
|
16
26
|
end
|
17
27
|
end
|
18
28
|
end
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -6,6 +6,7 @@ module Bolt
|
|
6
6
|
class Outputter
|
7
7
|
class Human < Bolt::Outputter
|
8
8
|
COLORS = {
|
9
|
+
dim: "2", # Dim, the other color of the rainbow
|
9
10
|
red: "31",
|
10
11
|
green: "32",
|
11
12
|
yellow: "33",
|
@@ -92,6 +93,10 @@ module Bolt
|
|
92
93
|
print_plan_start(event)
|
93
94
|
when :plan_finish
|
94
95
|
print_plan_finish(event)
|
96
|
+
when :container_start
|
97
|
+
print_container_start(event) if plan_logging?
|
98
|
+
when :container_finish
|
99
|
+
print_container_finish(event) if plan_logging?
|
95
100
|
when :start_spin
|
96
101
|
start_spin
|
97
102
|
when :stop_spin
|
@@ -112,6 +117,34 @@ module Bolt
|
|
112
117
|
@stream.puts(colorize(:green, "Started on #{target.safe_name}..."))
|
113
118
|
end
|
114
119
|
|
120
|
+
def print_container_result(result)
|
121
|
+
if result.success?
|
122
|
+
@stream.puts(colorize(:green, "Finished running container #{result.object}:"))
|
123
|
+
else
|
124
|
+
@stream.puts(colorize(:red, "Failed running container #{result.object}:"))
|
125
|
+
end
|
126
|
+
|
127
|
+
if result.error_hash
|
128
|
+
@stream.puts(colorize(:red, remove_trail(indent(2, result.error_hash['msg']))))
|
129
|
+
return 0
|
130
|
+
end
|
131
|
+
|
132
|
+
# Only print results if there's something other than empty string and hash
|
133
|
+
safe_value = result.safe_value
|
134
|
+
if safe_value['stdout'].strip.empty? && safe_value['stderr'].strip.empty?
|
135
|
+
@stream.puts(indent(2, "Running container #{result.object} completed successfully with no result"))
|
136
|
+
else
|
137
|
+
unless safe_value['stdout'].strip && safe_value['stdout'].strip.empty?
|
138
|
+
@stream.puts(indent(2, "STDOUT:"))
|
139
|
+
@stream.puts(indent(4, safe_value['stdout']))
|
140
|
+
end
|
141
|
+
unless safe_value['stderr'].strip.empty?
|
142
|
+
@stream.puts(indent(2, "STDERR:"))
|
143
|
+
@stream.puts(indent(4, safe_value['stderr']))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
115
148
|
def print_result(result)
|
116
149
|
if result.success?
|
117
150
|
@stream.puts(colorize(:green, "Finished on #{result.target.safe_name}:"))
|
@@ -142,16 +175,9 @@ module Bolt
|
|
142
175
|
end
|
143
176
|
|
144
177
|
# Use special handling if the result looks like a command or script result
|
145
|
-
if result.generic_value.keys == %w[stdout stderr exit_code]
|
178
|
+
if result.generic_value.keys == %w[stdout stderr merged_output exit_code]
|
146
179
|
safe_value = result.safe_value
|
147
|
-
unless safe_value['
|
148
|
-
@stream.puts(indent(2, "STDOUT:"))
|
149
|
-
@stream.puts(indent(4, safe_value['stdout']))
|
150
|
-
end
|
151
|
-
unless safe_value['stderr'].strip.empty?
|
152
|
-
@stream.puts(indent(2, "STDERR:"))
|
153
|
-
@stream.puts(indent(4, safe_value['stderr']))
|
154
|
-
end
|
180
|
+
@stream.puts(indent(2, safe_value['merged_output'])) unless safe_value['merged_output'].strip.empty?
|
155
181
|
elsif result.generic_value.any?
|
156
182
|
@stream.puts(indent(2, ::JSON.pretty_generate(result.generic_value)))
|
157
183
|
end
|
@@ -187,6 +213,25 @@ module Bolt
|
|
187
213
|
@stream.puts(colorize(:green, message))
|
188
214
|
end
|
189
215
|
|
216
|
+
def print_container_start(image:, **_kwargs)
|
217
|
+
@stream.puts(colorize(:green, "Starting: run container '#{image}'"))
|
218
|
+
end
|
219
|
+
|
220
|
+
def print_container_finish(event)
|
221
|
+
result = if event[:result].is_a?(Bolt::ContainerFailure)
|
222
|
+
event[:result].result
|
223
|
+
else
|
224
|
+
event[:result]
|
225
|
+
end
|
226
|
+
|
227
|
+
if result.success?
|
228
|
+
@stream.puts(colorize(:green, "Finished: run container '#{result.object}' succeeded."))
|
229
|
+
else
|
230
|
+
@stream.puts(colorize(:red, "Finished: run container '#{result.object}' failed."))
|
231
|
+
end
|
232
|
+
print_container_result(result) if @verbose
|
233
|
+
end
|
234
|
+
|
190
235
|
def print_plan_start(event)
|
191
236
|
@plan_depth += 1
|
192
237
|
# We use this event to both mark the start of a plan _and_ to enable
|
@@ -269,78 +314,115 @@ module Bolt
|
|
269
314
|
|
270
315
|
# @param [Hash] task A hash representing the task
|
271
316
|
def print_task_info(task)
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
317
|
+
params = (task.parameters || []).sort
|
318
|
+
|
319
|
+
info = +''
|
320
|
+
|
321
|
+
# Add task name and description
|
322
|
+
info << colorize(:cyan, "#{task.name}\n")
|
323
|
+
info << if task.description
|
324
|
+
indent(2, task.description.chomp)
|
277
325
|
else
|
278
|
-
|
326
|
+
indent(2, 'No description')
|
279
327
|
end
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
328
|
+
info << "\n\n"
|
329
|
+
|
330
|
+
# Build usage string
|
331
|
+
usage = +''
|
332
|
+
usage << if Bolt::Util.powershell?
|
333
|
+
"Invoke-BoltTask -Name #{task.name} -Targets <targets>"
|
334
|
+
else
|
335
|
+
"bolt task run #{task.name} --targets <targets>"
|
336
|
+
end
|
337
|
+
usage << (Bolt::Util.powershell? ? ' [-Noop]' : ' [--noop]') if task.supports_noop
|
338
|
+
params.each do |name, data|
|
339
|
+
usage << if data['type']&.start_with?('Optional')
|
340
|
+
" [#{name}=<value>]"
|
287
341
|
else
|
288
|
-
" #{
|
342
|
+
" #{name}=<value>"
|
289
343
|
end
|
290
344
|
end
|
291
345
|
|
292
|
-
|
293
|
-
|
346
|
+
# Add usage
|
347
|
+
info << colorize(:cyan, "Usage\n")
|
348
|
+
info << indent(2, wrap(usage))
|
349
|
+
info << "\n"
|
350
|
+
|
351
|
+
# Add parameters, if any
|
352
|
+
if params.any?
|
353
|
+
info << colorize(:cyan, "Parameters\n")
|
354
|
+
params.each do |name, data|
|
355
|
+
info << indent(2, "#{colorize(:yellow, name)} #{colorize(:dim, data['type'] || 'Any')}\n")
|
356
|
+
info << indent(4, "#{wrap(data['description']).chomp}\n") if data['description']
|
357
|
+
info << indent(4, "Default: #{data['default'].inspect}\n") if data.key?('default')
|
358
|
+
info << "\n"
|
359
|
+
end
|
294
360
|
end
|
295
361
|
|
296
|
-
|
297
|
-
task_info << " - #{task.description}" if task.description
|
298
|
-
task_info << "\n\n"
|
299
|
-
task_info << "USAGE:\n#{usage}\n\n"
|
300
|
-
task_info << "PARAMETERS:\n#{pretty_params}\n" unless pretty_params.empty?
|
301
|
-
task_info << "MODULE:\n"
|
302
|
-
|
362
|
+
# Add module location
|
303
363
|
path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
364
|
+
info << colorize(:cyan, "Module\n")
|
365
|
+
info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
366
|
+
indent(2, 'built-in module')
|
367
|
+
else
|
368
|
+
indent(2, path)
|
369
|
+
end
|
370
|
+
|
371
|
+
@stream.puts info
|
310
372
|
end
|
311
373
|
|
312
374
|
# @param [Hash] plan A hash representing the plan
|
313
375
|
def print_plan_info(plan)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
376
|
+
params = plan['parameters'].sort
|
377
|
+
|
378
|
+
info = +''
|
379
|
+
|
380
|
+
# Add plan name and description
|
381
|
+
info << colorize(:cyan, "#{plan['name']}\n")
|
382
|
+
info << if plan['description']
|
383
|
+
indent(2, plan['description'].chomp)
|
319
384
|
else
|
320
|
-
|
385
|
+
indent(2, 'No description')
|
321
386
|
end
|
387
|
+
info << "\n\n"
|
388
|
+
|
389
|
+
# Build the usage string
|
390
|
+
usage = +''
|
391
|
+
usage << if Bolt::Util.powershell?
|
392
|
+
"Invoke-BoltPlan -Name #{plan['name']}"
|
393
|
+
else
|
394
|
+
"bolt plan run #{plan['name']}"
|
395
|
+
end
|
396
|
+
params.each do |name, data|
|
397
|
+
usage << (data.include?('default_value') ? " [#{name}=<value>]" : " #{name}=<value>")
|
398
|
+
end
|
322
399
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
400
|
+
# Add usage
|
401
|
+
info << colorize(:cyan, "Usage\n")
|
402
|
+
info << indent(2, wrap(usage))
|
403
|
+
info << "\n"
|
404
|
+
|
405
|
+
# Add parameters, if any
|
406
|
+
if params.any?
|
407
|
+
info << colorize(:cyan, "Parameters\n")
|
408
|
+
|
409
|
+
params.each do |name, data|
|
410
|
+
info << indent(2, "#{colorize(:yellow, name)} #{colorize(:dim, data['type'])}\n")
|
411
|
+
info << indent(4, "#{wrap(data['description']).chomp}\n") if data['description']
|
412
|
+
info << indent(4, "Default: #{data['default_value']}\n") unless data['default_value'].nil?
|
413
|
+
info << "\n"
|
414
|
+
end
|
328
415
|
end
|
329
416
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
417
|
+
# Add module location
|
418
|
+
info << colorize(:cyan, "Module\n")
|
419
|
+
info << if plan['module'].start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
420
|
+
indent(2, 'built-in module')
|
421
|
+
else
|
422
|
+
indent(2, plan['module'])
|
423
|
+
end
|
336
424
|
|
337
|
-
|
338
|
-
plan_info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
339
|
-
"built-in module"
|
340
|
-
else
|
341
|
-
path
|
342
|
-
end
|
343
|
-
@stream.puts(plan_info)
|
425
|
+
@stream.puts info
|
344
426
|
end
|
345
427
|
|
346
428
|
def print_plans(plans, modulepath)
|
@@ -401,42 +483,115 @@ module Bolt
|
|
401
483
|
end
|
402
484
|
end
|
403
485
|
|
404
|
-
def print_targets(target_list,
|
486
|
+
def print_targets(target_list, inventory_source, default_inventory, target_flag)
|
405
487
|
adhoc = colorize(:yellow, "(Not found in inventory file)")
|
406
488
|
|
407
489
|
targets = []
|
408
490
|
targets += target_list[:inventory].map { |target| [target.name, nil] }
|
409
491
|
targets += target_list[:adhoc].map { |target| [target.name, adhoc] }
|
410
492
|
|
411
|
-
|
412
|
-
@stream.puts format_table(targets, 0, 2)
|
413
|
-
@stream.puts
|
414
|
-
end
|
493
|
+
info = +''
|
415
494
|
|
416
|
-
|
417
|
-
|
418
|
-
|
495
|
+
# Add target list
|
496
|
+
info << colorize(:cyan, "Targets\n")
|
497
|
+
info << if targets.any?
|
498
|
+
format_table(targets, 2, 2).to_s
|
499
|
+
else
|
500
|
+
indent(2, 'No targets')
|
501
|
+
end
|
502
|
+
info << "\n\n"
|
503
|
+
|
504
|
+
info << format_inventory_source(inventory_source, default_inventory)
|
505
|
+
info << format_target_summary(target_list[:inventory].count, target_list[:adhoc].count, target_flag, false)
|
506
|
+
|
507
|
+
@stream.puts info
|
508
|
+
end
|
509
|
+
|
510
|
+
def print_target_info(target_list, inventory_source, default_inventory, target_flag)
|
511
|
+
adhoc_targets = target_list[:adhoc].map(&:name).to_set
|
512
|
+
inventory_targets = target_list[:inventory].map(&:name).to_set
|
513
|
+
targets = target_list.values.flatten.sort_by(&:name)
|
514
|
+
|
515
|
+
info = +''
|
516
|
+
|
517
|
+
if targets.any?
|
518
|
+
adhoc = colorize(:yellow, " (Not found in inventory file)")
|
519
|
+
|
520
|
+
targets.each do |target|
|
521
|
+
info << colorize(:cyan, target.name)
|
522
|
+
info << adhoc if adhoc_targets.include?(target.name)
|
523
|
+
info << "\n"
|
524
|
+
info << indent(2, target.detail.to_yaml.lines.drop(1).join)
|
525
|
+
info << "\n"
|
526
|
+
end
|
419
527
|
else
|
420
|
-
|
528
|
+
info << colorize(:cyan, "Targets\n")
|
529
|
+
info << indent(2, "No targets\n\n")
|
421
530
|
end
|
422
531
|
|
423
|
-
|
424
|
-
|
425
|
-
|
532
|
+
info << format_inventory_source(inventory_source, default_inventory)
|
533
|
+
info << format_target_summary(inventory_targets.count, adhoc_targets.count, target_flag, true)
|
534
|
+
|
535
|
+
@stream.puts info
|
426
536
|
end
|
427
537
|
|
428
|
-
def
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
538
|
+
private def format_inventory_source(inventory_source, default_inventory)
|
539
|
+
info = +''
|
540
|
+
|
541
|
+
# Add inventory file source
|
542
|
+
info << colorize(:cyan, "Inventory source\n")
|
543
|
+
info << if inventory_source
|
544
|
+
indent(2, "#{inventory_source}\n")
|
545
|
+
else
|
546
|
+
indent(2, wrap("Tried to load inventory from #{default_inventory}, but the file does not exist\n"))
|
547
|
+
end
|
548
|
+
info << "\n"
|
434
549
|
end
|
435
550
|
|
436
|
-
def
|
437
|
-
|
438
|
-
|
439
|
-
|
551
|
+
private def format_target_summary(inventory_count, adhoc_count, target_flag, detail_flag)
|
552
|
+
info = +''
|
553
|
+
|
554
|
+
# Add target count summary
|
555
|
+
count = "#{inventory_count + adhoc_count} total, "\
|
556
|
+
"#{inventory_count} from inventory, "\
|
557
|
+
"#{adhoc_count} adhoc"
|
558
|
+
info << colorize(:cyan, "Target count\n")
|
559
|
+
info << indent(2, count)
|
560
|
+
|
561
|
+
# Add filtering information
|
562
|
+
unless target_flag && detail_flag
|
563
|
+
info << colorize(:cyan, "\n\nAdditional information\n")
|
564
|
+
|
565
|
+
unless target_flag
|
566
|
+
opt = Bolt::Util.windows? ? "'-Targets', '-Query', or '-Rerun'" : "'--targets', '--query', or '--rerun'"
|
567
|
+
info << indent(2, "Use the #{opt} option to view specific targets\n")
|
568
|
+
end
|
569
|
+
|
570
|
+
unless detail_flag
|
571
|
+
opt = Bolt::Util.windows? ? '-Detail' : '--detail'
|
572
|
+
info << indent(2, "Use the '#{opt}' option to view target configuration and data")
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
info
|
577
|
+
end
|
578
|
+
|
579
|
+
def print_groups(groups, inventory_source, default_inventory)
|
580
|
+
info = +''
|
581
|
+
|
582
|
+
# Add group list
|
583
|
+
info << colorize(:cyan, "Groups\n")
|
584
|
+
info << indent(2, groups.join("\n"))
|
585
|
+
info << "\n\n"
|
586
|
+
|
587
|
+
# Add inventory file source
|
588
|
+
info << format_inventory_source(inventory_source, default_inventory)
|
589
|
+
|
590
|
+
# Add group count summary
|
591
|
+
info << colorize(:cyan, "Group count\n")
|
592
|
+
info << indent(2, "#{groups.count} total")
|
593
|
+
|
594
|
+
@stream.puts info
|
440
595
|
end
|
441
596
|
|
442
597
|
# @param [Bolt::ResultSet] apply_result A ResultSet object representing the result of a `bolt apply`
|
@@ -452,6 +607,10 @@ module Bolt
|
|
452
607
|
@stream.puts("Plan completed successfully with no result")
|
453
608
|
when Bolt::ApplyFailure, Bolt::RunFailure
|
454
609
|
print_result_set(value.result_set)
|
610
|
+
when Bolt::ContainerResult
|
611
|
+
print_container_result(value)
|
612
|
+
when Bolt::ContainerFailure
|
613
|
+
print_container_result(value.result)
|
455
614
|
when Bolt::ResultSet
|
456
615
|
print_result_set(value)
|
457
616
|
else
|