bolt 3.6.1 → 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/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +66 -0
- data/guides/targets.txt +31 -0
- data/lib/bolt/bolt_option_parser.rb +35 -17
- data/lib/bolt/cli.rb +28 -7
- data/lib/bolt/inventory.rb +5 -4
- data/lib/bolt/inventory/inventory.rb +3 -2
- data/lib/bolt/outputter/human.rb +49 -24
- data/lib/bolt/outputter/json.rb +4 -4
- data/lib/bolt/pal/yaml_plan/step.rb +4 -2
- data/lib/bolt/plan_creator.rb +2 -2
- data/lib/bolt/puppetdb/client.rb +54 -0
- data/lib/bolt/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 575cccb1487a82a6537a83d5d23a89d9e3ed44898af25e2fe34acda2ecd765ae
|
4
|
+
data.tar.gz: a9de53717fdcb5380f95ef5ee1fb26b3d28eaa59f92355d9558954d14192f307
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60378d6872763f5fb557deae88207c29db0626d90562e37d80df1f604368629049da79ff0a0216602057566c7eb10892855f33a99b03bfc348fce8b443e7682d
|
7
|
+
data.tar.gz: e2f8dd460e346648e53921e299db5b7beaf4ba1a0cd7efe95728e2e2d42c3e4b3624c40ef8a94a21b7e4be5003d67a1a64c48d1a36a9e314c4d7bb296ce85eab
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
|
5
|
+
# Send a command with a payload to PuppetDB.
|
6
|
+
#
|
7
|
+
# The `pdb_command` function only supports version 5 of the `replace_facts`
|
8
|
+
# command. Other commands might also work, but are not tested or supported
|
9
|
+
# by Bolt.
|
10
|
+
#
|
11
|
+
# See the [commands endpoint](https://puppet.com/docs/puppetdb/latest/api/command/v1/commands.html)
|
12
|
+
# documentation for more information about available commands and payload
|
13
|
+
# format.
|
14
|
+
#
|
15
|
+
# _This function is experimental and subject to change._
|
16
|
+
#
|
17
|
+
# > **Note:** Not available in apply block
|
18
|
+
#
|
19
|
+
Puppet::Functions.create_function(:puppetdb_command) do
|
20
|
+
# @param command The command to invoke.
|
21
|
+
# @param version The version of the command to invoke.
|
22
|
+
# @param payload The payload to the command.
|
23
|
+
# @return The UUID identifying the response sent by PuppetDB.
|
24
|
+
# @example Replace facts for a target
|
25
|
+
# $payload = {
|
26
|
+
# 'certname' => 'localhost',
|
27
|
+
# 'environment' => 'dev',
|
28
|
+
# 'producer' => 'bolt',
|
29
|
+
# 'producer_timestamp' => '1970-01-01',
|
30
|
+
# 'values' => { 'orchestrator' => 'bolt' }
|
31
|
+
# }
|
32
|
+
#
|
33
|
+
# puppetdb_command('replace_facts', 5, $payload)
|
34
|
+
dispatch :puppetdb_command do
|
35
|
+
param 'String[1]', :command
|
36
|
+
param 'Integer', :version
|
37
|
+
param 'Hash[Data, Data]', :payload
|
38
|
+
return_type 'String'
|
39
|
+
end
|
40
|
+
|
41
|
+
def puppetdb_command(command, version, payload)
|
42
|
+
# Disallow in apply blocks.
|
43
|
+
unless Puppet[:tasks]
|
44
|
+
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
45
|
+
Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
|
46
|
+
action: 'puppetdb_command'
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Send analytics report.
|
51
|
+
Puppet.lookup(:bolt_executor).report_function_call(self.class.name)
|
52
|
+
|
53
|
+
puppetdb_client = Puppet.lookup(:bolt_pdb_client)
|
54
|
+
|
55
|
+
# Error if the PDB client does not implement :send_command
|
56
|
+
unless puppetdb_client.respond_to?(:send_command)
|
57
|
+
raise Bolt::Error.new(
|
58
|
+
"PuppetDB client #{puppetdb_client.class} does not implement :send_command, "\
|
59
|
+
"unable to invoke command.",
|
60
|
+
'bolt/pdb-command'
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
puppetdb_client.send_command(command, version, payload)
|
65
|
+
end
|
66
|
+
end
|
data/guides/targets.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
TOPIC
|
2
|
+
targets
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
A target is a device that Bolt connects to and runs actions on. Targets can
|
6
|
+
be physical, such as servers, or virtual, such as containers or virtual
|
7
|
+
machines.
|
8
|
+
|
9
|
+
Several of Bolt's commands connect to targets and run actions on them. When
|
10
|
+
you run these commands, Bolt requires a list of targets to run the action
|
11
|
+
on. For example, the `bolt script run` command and `Invoke-BoltScript`
|
12
|
+
PowerShell cmdlet require you to provide a list of targets to run your
|
13
|
+
script on. You can provide a list of targets to a command using one of the
|
14
|
+
following command-line options:
|
15
|
+
|
16
|
+
Shell commands
|
17
|
+
-t, --targets TARGETS
|
18
|
+
-q, --query QUERY
|
19
|
+
--rerun FILTER
|
20
|
+
|
21
|
+
PowerShell cmdlets
|
22
|
+
-T, -Targets TARGETS
|
23
|
+
-Q, -Query QUERY
|
24
|
+
-Rerun FILTER
|
25
|
+
|
26
|
+
Typically, targets and their configuration and data are listed in a
|
27
|
+
project's inventory file. For more information about inventory files,
|
28
|
+
see 'bolt guide inventory'.
|
29
|
+
|
30
|
+
DOCUMENTATION
|
31
|
+
https://pup.pt/bolt-commands
|
@@ -190,7 +190,8 @@ module Bolt
|
|
190
190
|
apply
|
191
191
|
|
192
192
|
USAGE
|
193
|
-
bolt apply [manifest
|
193
|
+
bolt apply [manifest] {--targets TARGETS | --query QUERY | --rerun FILTER}
|
194
|
+
[options]
|
194
195
|
|
195
196
|
DESCRIPTION
|
196
197
|
Apply Puppet manifest code on the specified targets.
|
@@ -219,7 +220,8 @@ module Bolt
|
|
219
220
|
run
|
220
221
|
|
221
222
|
USAGE
|
222
|
-
bolt command run <command>
|
223
|
+
bolt command run <command> {--targets TARGETS | --query QUERY | --rerun FILTER}
|
224
|
+
[options]
|
223
225
|
|
224
226
|
DESCRIPTION
|
225
227
|
Run a command on the specified targets.
|
@@ -248,7 +250,8 @@ module Bolt
|
|
248
250
|
download
|
249
251
|
|
250
252
|
USAGE
|
251
|
-
bolt file download <
|
253
|
+
bolt file download <source> <destination> {--targets TARGETS | --query QUERY | --rerun FILTER}
|
254
|
+
[options]
|
252
255
|
|
253
256
|
DESCRIPTION
|
254
257
|
Download a file or directory from one or more targets.
|
@@ -267,7 +270,8 @@ module Bolt
|
|
267
270
|
upload
|
268
271
|
|
269
272
|
USAGE
|
270
|
-
bolt file upload <
|
273
|
+
bolt file upload <source> <destination> {--targets TARGETS | --query QUERY | --rerun FILTER}
|
274
|
+
[options]
|
271
275
|
|
272
276
|
DESCRIPTION
|
273
277
|
Upload a local file or directory.
|
@@ -343,7 +347,12 @@ module Bolt
|
|
343
347
|
bolt inventory show [options]
|
344
348
|
|
345
349
|
DESCRIPTION
|
346
|
-
Show the list of targets an action would run on.
|
350
|
+
Show the list of targets an action would run on. This command will list
|
351
|
+
all targets in the project's inventory by default.
|
352
|
+
|
353
|
+
To filter the targets in the list, use the --targets, --query, or --rerun
|
354
|
+
options. To view detailed configuration and data for targets, use the
|
355
|
+
--detail option.
|
347
356
|
HELP
|
348
357
|
|
349
358
|
MODULE_HELP = <<~HELP
|
@@ -432,7 +441,7 @@ module Bolt
|
|
432
441
|
plan
|
433
442
|
|
434
443
|
USAGE
|
435
|
-
bolt plan <action> [
|
444
|
+
bolt plan <action> [options]
|
436
445
|
|
437
446
|
DESCRIPTION
|
438
447
|
Convert, create, show, and run Bolt plans.
|
@@ -449,16 +458,18 @@ module Bolt
|
|
449
458
|
convert
|
450
459
|
|
451
460
|
USAGE
|
452
|
-
bolt plan convert <
|
461
|
+
bolt plan convert <plan name> [options]
|
453
462
|
|
454
463
|
DESCRIPTION
|
455
|
-
Convert a YAML plan to a Puppet language plan and print the converted
|
464
|
+
Convert a YAML plan to a Puppet language plan and print the converted
|
465
|
+
plan to stdout.
|
456
466
|
|
457
467
|
Converting a YAML plan might result in a plan that is syntactically
|
458
468
|
correct but has different behavior. Always verify a converted plan's
|
459
469
|
functionality. Note that the converted plan is not written to a file.
|
460
470
|
|
461
471
|
EXAMPLES
|
472
|
+
bolt plan convert myproject::myplan
|
462
473
|
bolt plan convert path/to/plan/myplan.yaml
|
463
474
|
HELP
|
464
475
|
|
@@ -467,7 +478,7 @@ module Bolt
|
|
467
478
|
new
|
468
479
|
|
469
480
|
USAGE
|
470
|
-
bolt plan new <plan> [options]
|
481
|
+
bolt plan new <plan name> [options]
|
471
482
|
|
472
483
|
DESCRIPTION
|
473
484
|
Create a new plan in the current project.
|
@@ -481,7 +492,7 @@ module Bolt
|
|
481
492
|
run
|
482
493
|
|
483
494
|
USAGE
|
484
|
-
bolt plan run <plan> [parameters] [options]
|
495
|
+
bolt plan run <plan name> [parameters] [options]
|
485
496
|
|
486
497
|
DESCRIPTION
|
487
498
|
Run a plan on the specified targets.
|
@@ -495,7 +506,7 @@ module Bolt
|
|
495
506
|
show
|
496
507
|
|
497
508
|
USAGE
|
498
|
-
bolt plan show [plan] [options]
|
509
|
+
bolt plan show [plan name] [options]
|
499
510
|
|
500
511
|
DESCRIPTION
|
501
512
|
Show available plans and plan documentation.
|
@@ -557,7 +568,8 @@ module Bolt
|
|
557
568
|
bolt project migrate [options]
|
558
569
|
|
559
570
|
DESCRIPTION
|
560
|
-
Migrate a Bolt project to use current best practices and the latest version of
|
571
|
+
Migrate a Bolt project to use current best practices and the latest version of
|
572
|
+
configuration files.
|
561
573
|
HELP
|
562
574
|
|
563
575
|
SCRIPT_HELP = <<~HELP
|
@@ -579,7 +591,8 @@ module Bolt
|
|
579
591
|
run
|
580
592
|
|
581
593
|
USAGE
|
582
|
-
bolt script run <script> [arguments]
|
594
|
+
bolt script run <script> [arguments] {--targets TARGETS | --query QUERY | --rerun FILTER}
|
595
|
+
[options]
|
583
596
|
|
584
597
|
DESCRIPTION
|
585
598
|
Run a script on the specified targets.
|
@@ -661,7 +674,8 @@ module Bolt
|
|
661
674
|
run
|
662
675
|
|
663
676
|
USAGE
|
664
|
-
bolt task run <task> [parameters]
|
677
|
+
bolt task run <task name> [parameters] {--targets TARGETS | --query QUERY | --rerun FILTER}
|
678
|
+
[options]
|
665
679
|
|
666
680
|
DESCRIPTION
|
667
681
|
Run a task on the specified targets.
|
@@ -677,7 +691,7 @@ module Bolt
|
|
677
691
|
show
|
678
692
|
|
679
693
|
USAGE
|
680
|
-
bolt task show [task] [options]
|
694
|
+
bolt task show [task name] [options]
|
681
695
|
|
682
696
|
DESCRIPTION
|
683
697
|
Show available tasks and task documentation.
|
@@ -710,7 +724,8 @@ module Bolt
|
|
710
724
|
"SSH is the default protocol; can be #{TRANSPORTS.keys.join(', ')}",
|
711
725
|
'For Windows targets, specify the winrm:// protocol if it has not be configured',
|
712
726
|
'For SSH, port defaults to `22`',
|
713
|
-
'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting'
|
727
|
+
'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting',
|
728
|
+
"For more information, see 'bolt guide targets'.") do |targets|
|
714
729
|
@options[:targets] ||= []
|
715
730
|
@options[:targets] << Bolt::Util.get_arg_input(targets)
|
716
731
|
end
|
@@ -888,7 +903,10 @@ module Bolt
|
|
888
903
|
define('-v', '--[no-]verbose', 'Display verbose logging') do |value|
|
889
904
|
@options[:verbose] = value
|
890
905
|
end
|
891
|
-
define('--stream',
|
906
|
+
define('--stream',
|
907
|
+
'Stream output from scripts and commands to the console.',
|
908
|
+
'Run with --no-verbose to prevent Bolt from displaying output',
|
909
|
+
'a second time after the action is completed.') do |_|
|
892
910
|
@options[:stream] = true
|
893
911
|
end
|
894
912
|
define('--trace', 'Display error stack traces') do |_|
|
data/lib/bolt/cli.rb
CHANGED
@@ -47,6 +47,8 @@ module Bolt
|
|
47
47
|
'guide' => %w[]
|
48
48
|
}.freeze
|
49
49
|
|
50
|
+
TARGETING_OPTIONS = %i[query rerun targets].freeze
|
51
|
+
|
50
52
|
attr_reader :config, :options
|
51
53
|
|
52
54
|
def initialize(argv)
|
@@ -262,7 +264,7 @@ module Bolt
|
|
262
264
|
end
|
263
265
|
|
264
266
|
def update_targets(options)
|
265
|
-
target_opts = options.keys.select { |opt|
|
267
|
+
target_opts = options.keys.select { |opt| TARGETING_OPTIONS.include?(opt) }
|
266
268
|
target_string = "'--targets', '--rerun', or '--query'"
|
267
269
|
if target_opts.length > 1
|
268
270
|
raise Bolt::CLIError, "Only one targeting option #{target_string} can be specified"
|
@@ -634,13 +636,33 @@ module Bolt
|
|
634
636
|
end
|
635
637
|
|
636
638
|
def list_targets
|
637
|
-
|
638
|
-
|
639
|
+
if options.keys.any? { |key| TARGETING_OPTIONS.include?(key) }
|
640
|
+
target_flag = true
|
641
|
+
else
|
642
|
+
options[:targets] = 'all'
|
643
|
+
end
|
644
|
+
|
645
|
+
outputter.print_targets(
|
646
|
+
group_targets_by_source,
|
647
|
+
inventory.source,
|
648
|
+
config.default_inventoryfile,
|
649
|
+
target_flag
|
650
|
+
)
|
639
651
|
end
|
640
652
|
|
641
653
|
def show_targets
|
642
|
-
|
643
|
-
|
654
|
+
if options.keys.any? { |key| TARGETING_OPTIONS.include?(key) }
|
655
|
+
target_flag = true
|
656
|
+
else
|
657
|
+
options[:targets] = 'all'
|
658
|
+
end
|
659
|
+
|
660
|
+
outputter.print_target_info(
|
661
|
+
group_targets_by_source,
|
662
|
+
inventory.source,
|
663
|
+
config.default_inventoryfile,
|
664
|
+
target_flag
|
665
|
+
)
|
644
666
|
end
|
645
667
|
|
646
668
|
# Returns a hash of targets sorted by those that are found in the
|
@@ -661,8 +683,7 @@ module Bolt
|
|
661
683
|
end
|
662
684
|
|
663
685
|
def list_groups
|
664
|
-
|
665
|
-
outputter.print_groups(groups)
|
686
|
+
outputter.print_groups(inventory.group_names.sort, inventory.source, config.default_inventoryfile)
|
666
687
|
end
|
667
688
|
|
668
689
|
def run_plan(plan_name, plan_arguments, nodes, options)
|
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
|
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -483,7 +483,7 @@ module Bolt
|
|
483
483
|
end
|
484
484
|
end
|
485
485
|
|
486
|
-
def print_targets(target_list,
|
486
|
+
def print_targets(target_list, inventory_source, default_inventory, target_flag)
|
487
487
|
adhoc = colorize(:yellow, "(Not found in inventory file)")
|
488
488
|
|
489
489
|
targets = []
|
@@ -501,16 +501,13 @@ module Bolt
|
|
501
501
|
end
|
502
502
|
info << "\n\n"
|
503
503
|
|
504
|
-
|
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)
|
505
506
|
|
506
|
-
|
507
|
-
target_list[:inventory].count,
|
508
|
-
target_list[:adhoc].count,
|
509
|
-
inventoryfile
|
510
|
-
)
|
507
|
+
@stream.puts info
|
511
508
|
end
|
512
509
|
|
513
|
-
def print_target_info(target_list,
|
510
|
+
def print_target_info(target_list, inventory_source, default_inventory, target_flag)
|
514
511
|
adhoc_targets = target_list[:adhoc].map(&:name).to_set
|
515
512
|
inventory_targets = target_list[:inventory].map(&:name).to_set
|
516
513
|
targets = target_list.values.flatten.sort_by(&:name)
|
@@ -532,26 +529,27 @@ module Bolt
|
|
532
529
|
info << indent(2, "No targets\n\n")
|
533
530
|
end
|
534
531
|
|
535
|
-
|
532
|
+
info << format_inventory_source(inventory_source, default_inventory)
|
533
|
+
info << format_target_summary(inventory_targets.count, adhoc_targets.count, target_flag, true)
|
536
534
|
|
537
|
-
|
538
|
-
inventory_targets.count,
|
539
|
-
adhoc_targets.count,
|
540
|
-
inventoryfile
|
541
|
-
)
|
535
|
+
@stream.puts info
|
542
536
|
end
|
543
537
|
|
544
|
-
private def
|
538
|
+
private def format_inventory_source(inventory_source, default_inventory)
|
545
539
|
info = +''
|
546
540
|
|
547
541
|
# Add inventory file source
|
548
|
-
info << colorize(:cyan, "Inventory
|
549
|
-
info << if
|
550
|
-
indent(2, "#{
|
542
|
+
info << colorize(:cyan, "Inventory source\n")
|
543
|
+
info << if inventory_source
|
544
|
+
indent(2, "#{inventory_source}\n")
|
551
545
|
else
|
552
|
-
indent(2, wrap("Tried to load inventory from #{
|
546
|
+
indent(2, wrap("Tried to load inventory from #{default_inventory}, but the file does not exist\n"))
|
553
547
|
end
|
554
548
|
info << "\n"
|
549
|
+
end
|
550
|
+
|
551
|
+
private def format_target_summary(inventory_count, adhoc_count, target_flag, detail_flag)
|
552
|
+
info = +''
|
555
553
|
|
556
554
|
# Add target count summary
|
557
555
|
count = "#{inventory_count + adhoc_count} total, "\
|
@@ -560,13 +558,40 @@ module Bolt
|
|
560
558
|
info << colorize(:cyan, "Target count\n")
|
561
559
|
info << indent(2, count)
|
562
560
|
|
563
|
-
|
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
|
564
577
|
end
|
565
578
|
|
566
|
-
def print_groups(groups)
|
567
|
-
|
568
|
-
|
569
|
-
|
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
|
570
595
|
end
|
571
596
|
|
572
597
|
# @param [Bolt::ResultSet] apply_result A ResultSet object representing the result of a `bolt apply`
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -100,12 +100,12 @@ module Bolt
|
|
100
100
|
moduledir: moduledir.to_s }.to_json)
|
101
101
|
end
|
102
102
|
|
103
|
-
def print_targets(target_list,
|
103
|
+
def print_targets(target_list, inventory_source, default_inventory, _target_flag)
|
104
104
|
@stream.puts ::JSON.pretty_generate(
|
105
105
|
inventory: {
|
106
106
|
targets: target_list[:inventory].map(&:name),
|
107
107
|
count: target_list[:inventory].count,
|
108
|
-
file:
|
108
|
+
file: (inventory_source || default_inventory).to_s
|
109
109
|
},
|
110
110
|
adhoc: {
|
111
111
|
targets: target_list[:adhoc].map(&:name),
|
@@ -116,7 +116,7 @@ module Bolt
|
|
116
116
|
)
|
117
117
|
end
|
118
118
|
|
119
|
-
def print_target_info(target_list,
|
119
|
+
def print_target_info(target_list, _inventory_source, _default_inventory, _target_flag)
|
120
120
|
targets = target_list.values.flatten
|
121
121
|
|
122
122
|
@stream.puts ::JSON.pretty_generate(
|
@@ -125,7 +125,7 @@ module Bolt
|
|
125
125
|
)
|
126
126
|
end
|
127
127
|
|
128
|
-
def print_groups(groups)
|
128
|
+
def print_groups(groups, _inventory_source, _default_inventory)
|
129
129
|
count = groups.count
|
130
130
|
@stream.puts({ groups: groups,
|
131
131
|
count: count }.to_json)
|
@@ -122,9 +122,11 @@ module Bolt
|
|
122
122
|
raise StepError.new("Parameters key must be a hash", body['name'], step_number)
|
123
123
|
end
|
124
124
|
|
125
|
-
metaparams =
|
125
|
+
metaparams = body['parameters'].keys
|
126
|
+
.select { |key| key.start_with?('_') }
|
127
|
+
.map { |key| key.sub(/^_/, '') }
|
126
128
|
|
127
|
-
if (dups = body
|
129
|
+
if (dups = body.keys & metaparams).any?
|
128
130
|
raise StepError.new(
|
129
131
|
"Cannot specify metaparameters when using top-level keys with same name: #{dups.join(', ')}",
|
130
132
|
body['name'],
|
data/lib/bolt/plan_creator.rb
CHANGED
@@ -36,8 +36,8 @@ module Bolt
|
|
36
36
|
prefix, _, basename = segment_plan_name(plan_name)
|
37
37
|
|
38
38
|
unless prefix == project.name
|
39
|
-
message = "
|
40
|
-
|
39
|
+
message = "Incomplete plan name: A plan name must be prefixed with the name of the "\
|
40
|
+
"project or module. Did you mean '#{project.name}::#{plan_name}'?"
|
41
41
|
|
42
42
|
raise Bolt::ValidationError, message
|
43
43
|
end
|
data/lib/bolt/puppetdb/client.rb
CHANGED
@@ -95,6 +95,60 @@ module Bolt
|
|
95
95
|
make_query(query, path)
|
96
96
|
end
|
97
97
|
|
98
|
+
# Sends a command to PuppetDB using version 1 of the commands API.
|
99
|
+
# https://puppet.com/docs/puppetdb/latest/api/command/v1/commands.html
|
100
|
+
#
|
101
|
+
# @param command [String] The command to invoke.
|
102
|
+
# @param version [Integer] The version of the command to invoke.
|
103
|
+
# @param payload [Hash] The payload to send with the command.
|
104
|
+
# @return A UUID identifying the submitted command.
|
105
|
+
#
|
106
|
+
def send_command(command, version, payload)
|
107
|
+
command = command.dup.force_encoding('utf-8')
|
108
|
+
body = JSON.generate(payload)
|
109
|
+
|
110
|
+
# PDB requires the following query parameters to the POST request.
|
111
|
+
# Error early if there's no certname, as PDB does not return a
|
112
|
+
# message indicating it's required.
|
113
|
+
unless payload['certname']
|
114
|
+
raise Bolt::Error.new(
|
115
|
+
"Payload must include 'certname', unable to invoke command.",
|
116
|
+
'bolt/pdb-command'
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
url = uri.tap do |u|
|
121
|
+
u.path = 'pdb/cmd/v1'
|
122
|
+
u.query_values = { 'command' => command,
|
123
|
+
'version' => version,
|
124
|
+
'certname' => payload['certname'] }
|
125
|
+
end
|
126
|
+
|
127
|
+
# Send the command to PDB
|
128
|
+
begin
|
129
|
+
@logger.debug("Sending PuppetDB command '#{command}' to #{url}")
|
130
|
+
response = http_client.post(url.to_s, body: body, header: headers)
|
131
|
+
rescue StandardError => e
|
132
|
+
raise Bolt::PuppetDBFailoverError, "Failed to invoke PuppetDB command: #{e}"
|
133
|
+
end
|
134
|
+
|
135
|
+
@logger.debug("Got response code #{response.code} from PuppetDB")
|
136
|
+
if response.code != 200
|
137
|
+
raise Bolt::PuppetDBError, "Failed to invoke PuppetDB command: #{response.body}"
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return the UUID string from the response body
|
141
|
+
begin
|
142
|
+
JSON.parse(response.body).fetch('uuid', nil)
|
143
|
+
rescue JSON::ParserError
|
144
|
+
raise Bolt::PuppetDBError, "Unable to parse response as JSON: #{response.body}"
|
145
|
+
end
|
146
|
+
rescue Bolt::PuppetDBFailoverError => e
|
147
|
+
@logger.error("Request to puppetdb at #{@current_url} failed with #{e}.")
|
148
|
+
reject_url
|
149
|
+
send_command(command, version, payload)
|
150
|
+
end
|
151
|
+
|
98
152
|
def http_client
|
99
153
|
return @http if @http
|
100
154
|
# lazy-load expensive gem code
|
data/lib/bolt/version.rb
CHANGED
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: 3.
|
4
|
+
version: 3.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-04-
|
11
|
+
date: 2021-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -414,6 +414,7 @@ files:
|
|
414
414
|
- bolt-modules/boltlib/lib/puppet/functions/get_target.rb
|
415
415
|
- bolt-modules/boltlib/lib/puppet/functions/get_targets.rb
|
416
416
|
- bolt-modules/boltlib/lib/puppet/functions/parallelize.rb
|
417
|
+
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb
|
417
418
|
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb
|
418
419
|
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb
|
419
420
|
- bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb
|
@@ -454,6 +455,7 @@ files:
|
|
454
455
|
- guides/module.txt
|
455
456
|
- guides/modulepath.txt
|
456
457
|
- guides/project.txt
|
458
|
+
- guides/targets.txt
|
457
459
|
- lib/bolt.rb
|
458
460
|
- lib/bolt/analytics.rb
|
459
461
|
- lib/bolt/applicator.rb
|