bolt 3.22.1 → 3.24.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.

Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +9 -9
  3. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +32 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +20 -1
  5. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +23 -1
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +28 -23
  7. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +22 -19
  8. data/lib/bolt/application.rb +17 -10
  9. data/lib/bolt/applicator.rb +8 -2
  10. data/lib/bolt/bolt_option_parser.rb +4 -1
  11. data/lib/bolt/catalog.rb +1 -1
  12. data/lib/bolt/config/options.rb +65 -49
  13. data/lib/bolt/config/transport/local.rb +1 -0
  14. data/lib/bolt/config/transport/lxd.rb +9 -0
  15. data/lib/bolt/config.rb +12 -3
  16. data/lib/bolt/inventory/inventory.rb +30 -11
  17. data/lib/bolt/outputter/human.rb +10 -4
  18. data/lib/bolt/outputter/json.rb +3 -1
  19. data/lib/bolt/outputter/rainbow.rb +2 -1
  20. data/lib/bolt/pal/yaml_plan/loader.rb +1 -1
  21. data/lib/bolt/pal.rb +6 -2
  22. data/lib/bolt/plugin/puppetdb.rb +8 -5
  23. data/lib/bolt/plugin.rb +2 -1
  24. data/lib/bolt/puppetdb/client.rb +90 -129
  25. data/lib/bolt/puppetdb/config.rb +21 -8
  26. data/lib/bolt/puppetdb/instance.rb +146 -0
  27. data/lib/bolt/result.rb +1 -1
  28. data/lib/bolt/transport/orch/connection.rb +2 -1
  29. data/lib/bolt/transport/winrm/connection.rb +18 -11
  30. data/lib/bolt/version.rb +1 -1
  31. data/lib/bolt_server/file_cache.rb +10 -8
  32. data/lib/bolt_spec/plans/action_stubs/download_stub.rb +1 -1
  33. data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +1 -1
  34. data/lib/bolt_spec/plans/action_stubs/task_stub.rb +1 -1
  35. data/lib/bolt_spec/plans/action_stubs/upload_stub.rb +1 -1
  36. data/lib/bolt_spec/plans/action_stubs.rb +2 -2
  37. data/lib/bolt_spec/plans/mock_executor.rb +1 -1
  38. data/lib/bolt_spec/plans.rb +11 -1
  39. metadata +10 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb70cb2643e6f83db4c78140e69b63f1adb0547babb48a56f7263d6e231e190
4
- data.tar.gz: 87bac24240c774e3142631834692b1c1f03aacd28ec35bb1ef33693be42af1ba
3
+ metadata.gz: 7ad3bbc9413aac278feeac8a7e31173bd065f0029fb211d7e1906c4803a4c390
4
+ data.tar.gz: 387d3a07844139eb29a1db06d1792acfdad6a09eab2b5576a9c4d34fdffdaca8
5
5
  SHA512:
6
- metadata.gz: 9a5bdda010517568732212c1436560c952da36be78511cfaf2543ce7b330245d7c8d78ebf1c8c2a1feb986f2276d644edf54ccaa1c52cd4d1072954c3e644214
7
- data.tar.gz: cc5ec411b3b3d3772f89ce19cca8d3a9bf086c7b4da580c334ccb0c31c763a1641fe5972389a71e7874e64e10323ec7286027bc6c4b86447a8beb28cdb04796a
6
+ metadata.gz: 83c1685fc238f049dad5cf841ea55f37c57a1aa59d66ef420d754b78d7b0ba8cca4533accb2cfbe53915587f1832beb7cbf956501486de63e135933b57f5fa98
7
+ data.tar.gz: c6900fde1fd9234a603171c79c2f2b3a22b2d2661797b94bf0afd2050f4ef5cc32844562734d3e41bd94464806e1efaabaac346d6887773f547c801c33cc3d6f
data/Puppetfile CHANGED
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- forge "http://forge.puppetlabs.com"
3
+ forge 'https://forge.puppetlabs.com'
4
4
 
5
5
  moduledir File.join(File.dirname(__FILE__), 'modules')
6
6
 
7
7
  # Core modules used by 'apply'
8
- mod 'puppetlabs-service', '2.1.0'
9
- mod 'puppetlabs-puppet_agent', '4.9.0'
8
+ mod 'puppetlabs-service', '2.2.0'
9
+ mod 'puppetlabs-puppet_agent', '4.11.0'
10
10
  mod 'puppetlabs-facts', '1.4.0'
11
11
 
12
12
  # Core types and providers for Puppet 6
13
13
  mod 'puppetlabs-augeas_core', '1.2.0'
14
14
  mod 'puppetlabs-host_core', '1.1.0'
15
- mod 'puppetlabs-scheduled_task', '3.0.1'
15
+ mod 'puppetlabs-scheduled_task', '3.1.0'
16
16
  mod 'puppetlabs-sshkeys_core', '2.3.0'
17
17
  mod 'puppetlabs-zfs_core', '1.3.0'
18
18
  mod 'puppetlabs-cron_core', '1.1.0'
@@ -22,14 +22,14 @@ mod 'puppetlabs-yumrepo_core', '1.1.0'
22
22
  mod 'puppetlabs-zone_core', '1.0.3'
23
23
 
24
24
  # Useful additional modules
25
- mod 'puppetlabs-package', '2.1.0'
25
+ mod 'puppetlabs-package', '2.2.0'
26
26
  mod 'puppetlabs-powershell_task_helper', '0.1.0'
27
- mod 'puppetlabs-puppet_conf', '1.2.0'
27
+ mod 'puppetlabs-puppet_conf', '1.3.0'
28
28
  mod 'puppetlabs-python_task_helper', '0.5.0'
29
- mod 'puppetlabs-reboot', '4.1.0'
30
- mod 'puppetlabs-ruby_task_helper', '0.6.0'
29
+ mod 'puppetlabs-reboot', '4.2.0'
30
+ mod 'puppetlabs-ruby_task_helper', '0.6.1'
31
31
  mod 'puppetlabs-ruby_plugin_helper', '0.2.0'
32
- mod 'puppetlabs-stdlib', '8.1.0'
32
+ mod 'puppetlabs-stdlib', '8.2.0'
33
33
 
34
34
  # Plugin modules
35
35
  mod 'puppetlabs-aws_inventory', '0.7.0'
@@ -17,6 +17,8 @@ require 'bolt/error'
17
17
  # > **Note:** Not available in apply block
18
18
  #
19
19
  Puppet::Functions.create_function(:puppetdb_command) do
20
+ # Send a command with a payload to PuppetDB.
21
+ #
20
22
  # @param command The command to invoke.
21
23
  # @param version The version of the command to invoke.
22
24
  # @param payload The payload to the command.
@@ -38,7 +40,36 @@ Puppet::Functions.create_function(:puppetdb_command) do
38
40
  return_type 'String'
39
41
  end
40
42
 
43
+ # Send a command with a payload to a named PuppetDB instance.
44
+ #
45
+ # @param command The command to invoke.
46
+ # @param version The version of the command to invoke.
47
+ # @param payload The payload to the command.
48
+ # @param instance The PuppetDB instance to send the command to.
49
+ # @return The UUID identifying the response sent by PuppetDB.
50
+ # @example Replace facts for a target using a named PuppetDB instance
51
+ # $payload = {
52
+ # 'certname' => 'localhost',
53
+ # 'environment' => 'dev',
54
+ # 'producer' => 'bolt',
55
+ # 'producer_timestamp' => '1970-01-01',
56
+ # 'values' => { 'orchestrator' => 'bolt' }
57
+ # }
58
+ #
59
+ # puppetdb_command('replace_facts', 5, $payload, 'instance-1')
60
+ dispatch :puppetdb_command_with_instance do
61
+ param 'String[1]', :command
62
+ param 'Integer', :version
63
+ param 'Hash[Data, Data]', :payload
64
+ param 'String', :instance
65
+ return_type 'String'
66
+ end
67
+
41
68
  def puppetdb_command(command, version, payload)
69
+ puppetdb_command_with_instance(command, version, payload, nil)
70
+ end
71
+
72
+ def puppetdb_command_with_instance(command, version, payload, instance)
42
73
  # Disallow in apply blocks.
43
74
  unless Puppet[:tasks]
44
75
  raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
@@ -61,6 +92,6 @@ Puppet::Functions.create_function(:puppetdb_command) do
61
92
  )
62
93
  end
63
94
 
64
- puppetdb_client.send_command(command, version, payload)
95
+ puppetdb_client.send_command(command, version, payload, instance)
65
96
  end
66
97
  end
@@ -7,6 +7,8 @@ require 'bolt/error'
7
7
  # If a node is not found in PuppetDB, it's included in the returned hash with an empty facts hash.
8
8
  # Otherwise, the node is included in the hash with a value that is a hash of its facts.
9
9
  Puppet::Functions.create_function(:puppetdb_fact) do
10
+ # Collect facts from PuppetDB.
11
+ #
10
12
  # @param certnames Array of certnames.
11
13
  # @return A hash of certname to facts hash for each matched Target.
12
14
  # @example Get facts for nodes
@@ -16,13 +18,30 @@ Puppet::Functions.create_function(:puppetdb_fact) do
16
18
  return_type 'Hash[String, Data]'
17
19
  end
18
20
 
21
+ # Collects facts from a named PuppetDB instance.
22
+ #
23
+ # @param certnames Array of certnames.
24
+ # @param instance The PuppetDB instance to query.
25
+ # @return A hash of certname to facts hash for each matched Target.
26
+ # @example Get facts for nodes from a named PuppetDB instance
27
+ # puppetdb_fact(['app.example.com', 'db.example.com'], 'instance-1')
28
+ dispatch :puppetdb_fact_with_instance do
29
+ param 'Array[String]', :certnames
30
+ param 'String', :instance
31
+ return_type 'Hash[String, Data]'
32
+ end
33
+
19
34
  def puppetdb_fact(certnames)
35
+ puppetdb_fact_with_instance(certnames, nil)
36
+ end
37
+
38
+ def puppetdb_fact_with_instance(certnames, instance)
20
39
  puppetdb_client = Puppet.lookup(:bolt_pdb_client)
21
40
  # Bolt executor not expected when invoked from apply block
22
41
  executor = Puppet.lookup(:bolt_executor) { nil }
23
42
  # Send Analytics Report
24
43
  executor&.report_function_call(self.class.name)
25
44
 
26
- puppetdb_client.facts_for_node(certnames)
45
+ puppetdb_client.facts_for_node(certnames, instance)
27
46
  end
28
47
  end
@@ -6,6 +6,8 @@ require 'bolt/error'
6
6
  # using Bolt's PuppetDB client.
7
7
  Puppet::Functions.create_function(:puppetdb_query) do
8
8
  # rubocop:disable Layout/LineLength
9
+ # Make a query to PuppetDB.
10
+ #
9
11
  # @param query A PQL query.
10
12
  # Learn more about [Puppet's query language](https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html), PQL.
11
13
  # @return Results of the PuppetDB query.
@@ -16,15 +18,35 @@ Puppet::Functions.create_function(:puppetdb_query) do
16
18
  param 'Variant[String, Array[Data]]', :query
17
19
  return_type 'Array[Data]'
18
20
  end
21
+
22
+ # rubocop:disable Layout/LineLength
23
+ # Make a query to a named PuppetDB instance.
24
+ #
25
+ # @param query A PQL query.
26
+ # Learn more about [Puppet's query language](https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html), PQL.
27
+ # @param instance The PuppetDB instance to query.
28
+ # @return Results of the PuppetDB query.
29
+ # @example Request certnames for all nodes using a named PuppetDB instance
30
+ # puppetdb_query('nodes[certname] {}', 'instance-1')
31
+ # rubocop:enable Layout/LineLength
32
+ dispatch :make_query_with_instance do
33
+ param 'Variant[String, Array[Data]]', :query
34
+ param 'String', :instance
35
+ return_type 'Array[Data]'
36
+ end
19
37
  # The query type could be more specific ASTQuery = Array[Variant[String, ASTQuery]]
20
38
 
21
39
  def make_query(query)
40
+ make_query_with_instance(query, nil)
41
+ end
42
+
43
+ def make_query_with_instance(query, instance)
22
44
  puppetdb_client = Puppet.lookup(:bolt_pdb_client)
23
45
  # Bolt executor not expected when invoked from apply block
24
46
  executor = Puppet.lookup(:bolt_executor) { nil }
25
47
  # Send Analytics Report
26
48
  executor&.report_function_call(self.class.name)
27
49
 
28
- puppetdb_client.make_query(query)
50
+ puppetdb_client.make_query(query, nil, instance)
29
51
  end
30
52
  end
@@ -57,6 +57,7 @@ Puppet::Functions.create_function(:run_task) do
57
57
 
58
58
  options, params = args.partition { |k, _v| k.start_with?('_') }.map(&:to_h)
59
59
  options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
60
+ options[:description] = description if description
60
61
 
61
62
  executor = Puppet.lookup(:bolt_executor)
62
63
  inventory = Puppet.lookup(:bolt_inventory)
@@ -68,18 +69,24 @@ Puppet::Functions.create_function(:run_task) do
68
69
  executor.report_function_call(self.class.name)
69
70
  end
70
71
 
71
- # Report Analytics for bundled content, this should capture tasks run from both CLI and Plans
72
+ # Report Analytics for bundled content, this should capture tasks run from
73
+ # both CLI and Plans.
72
74
  executor.report_bundled_content('Task', task_name)
73
75
 
74
- # Ensure that given targets are all Target instances
76
+ # Ensure that given targets are all Target instances.
75
77
  targets = inventory.get_targets(targets)
76
78
 
77
- options[:description] = description if description
79
+ # Return early if there are no targets.
80
+ if targets.empty?
81
+ return Bolt::ResultSet.new([])
82
+ end
78
83
 
79
- # Don't bother loading the local task definition if all targets use the 'pcp' transport.
80
- if !targets.empty? && targets.all? { |t| t.transport == 'pcp' }
81
- # create a fake task
82
- task = Bolt::Task.new(task_name, {}, [{ 'name' => '', 'path' => '' }])
84
+ # If all targets use the PCP transport, create a fake task instead of
85
+ # loading the actual task definition.
86
+ if targets.all? { |t| t.transport == 'pcp' }
87
+ task = Bolt::Task.new(task_name,
88
+ { 'supports_noop' => true },
89
+ [{ 'name' => '', 'path' => '' }])
83
90
  else
84
91
  # TODO: use the compiler injection once PUP-8237 lands
85
92
  task_signature = Puppet::Pal::ScriptCompiler.new(closure_scope.compiler).task_signature(task_name)
@@ -89,7 +96,8 @@ Puppet::Functions.create_function(:run_task) do
89
96
 
90
97
  task = Bolt::Task.from_task_signature(task_signature)
91
98
 
92
- # Set the default value for any params that have one and were not provided or are undef
99
+ # Set the default value for any params that have one and were not provided
100
+ # or are undef.
93
101
  params = task.parameter_defaults.merge(params) do |_, default, passed|
94
102
  passed.nil? ? default : passed
95
103
  end
@@ -99,9 +107,9 @@ Puppet::Functions.create_function(:run_task) do
99
107
  end || (raise with_stack(:TYPE_MISMATCH, 'Task parameters do not match'))
100
108
  end
101
109
 
110
+ # Generate a helpful error message about the type-mismatch between the type
111
+ # Data and the actual type of params.
102
112
  unless Puppet::Pops::Types::TypeFactory.data.instance?(params)
103
- # generate a helpful error message about the type-mismatch between the type Data
104
- # and the actual type of params
105
113
  params_t = Puppet::Pops::Types::TypeCalculator.infer_set(params)
106
114
  desc = Puppet::Pops::Types::TypeMismatchDescriber.singleton.describe_mismatch(
107
115
  'Task parameters are not of type Data. run_task()',
@@ -133,23 +141,20 @@ Puppet::Functions.create_function(:run_task) do
133
141
  # Report whether the task was run in noop mode.
134
142
  executor.report_noop_mode(executor.noop || options[:noop])
135
143
 
136
- if targets.empty?
137
- Bolt::ResultSet.new([])
138
- else
139
- file_line = Puppet::Pops::PuppetStack.top_of_stack
140
- result = if executor.in_parallel?
141
- executor.run_in_thread do
142
- executor.run_task(targets, task, params, options, file_line)
143
- end
144
- else
144
+ file_line = Puppet::Pops::PuppetStack.top_of_stack
145
+ result = if executor.in_parallel?
146
+ executor.run_in_thread do
145
147
  executor.run_task(targets, task, params, options, file_line)
146
148
  end
149
+ else
150
+ executor.run_task(targets, task, params, options, file_line)
151
+ end
147
152
 
148
- if !result.ok && !options[:catch_errors]
149
- raise Bolt::RunFailure.new(result, 'run_task', task_name)
150
- end
151
- result
153
+ if !result.ok && !options[:catch_errors]
154
+ raise Bolt::RunFailure.new(result, 'run_task', task_name)
152
155
  end
156
+
157
+ result
153
158
  end
154
159
 
155
160
  def with_stack(kind, msg)
@@ -92,10 +92,17 @@ Puppet::Functions.create_function(:run_task_with) do
92
92
  # Get all the targets
93
93
  targets = Array(inventory.get_targets(targets))
94
94
 
95
+ # Return early if there are no targets.
96
+ if targets.empty?
97
+ return Bolt::ResultSet.new([])
98
+ end
99
+
95
100
  # If all targets use the 'pcp' transport, use a fake task instead of loading the local definition
96
101
  # Otherwise, load the local task definition
97
- if (pcp_only = targets.any? && targets.all? { |t| t.transport == 'pcp' })
98
- task = Bolt::Task.new(task_name, {}, [{ 'name' => '', 'path' => '' }])
102
+ if (pcp_only = targets.all? { |t| t.transport == 'pcp' })
103
+ task = Bolt::Task.new(task_name,
104
+ { 'supports_noop' => true },
105
+ [{ 'name' => '', 'path' => '' }])
99
106
  else
100
107
  task_signature = Puppet::Pal::ScriptCompiler.new(closure_scope.compiler).task_signature(task_name)
101
108
 
@@ -178,27 +185,23 @@ Puppet::Functions.create_function(:run_task_with) do
178
185
  # Report whether the task was run in noop mode.
179
186
  executor.report_noop_mode(executor.noop || options[:noop])
180
187
 
181
- if targets.empty?
182
- Bolt::ResultSet.new([])
183
- else
184
- # Combine the results from the task run with any failing results that were
185
- # generated earlier when creating the target mapping
186
- file_line = Puppet::Pops::PuppetStack.top_of_stack
187
- task_result = if executor.in_parallel?
188
- executor.run_in_thread do
189
- executor.run_task_with(target_mapping, task, options, file_line)
190
- end
191
- else
188
+ # Combine the results from the task run with any failing results that were
189
+ # generated earlier when creating the target mapping
190
+ file_line = Puppet::Pops::PuppetStack.top_of_stack
191
+ task_result = if executor.in_parallel?
192
+ executor.run_in_thread do
192
193
  executor.run_task_with(target_mapping, task, options, file_line)
193
194
  end
194
- result = Bolt::ResultSet.new(task_result.results + error_set)
195
-
196
- if !result.ok && !options[:catch_errors]
197
- raise Bolt::RunFailure.new(result, 'run_task', task_name)
198
- end
195
+ else
196
+ executor.run_task_with(target_mapping, task, options, file_line)
197
+ end
198
+ result = Bolt::ResultSet.new(task_result.results + error_set)
199
199
 
200
- result
200
+ if !result.ok && !options[:catch_errors]
201
+ raise Bolt::RunFailure.new(result, 'run_task', task_name)
201
202
  end
203
+
204
+ result
202
205
  end
203
206
 
204
207
  def with_stack(kind, msg)
@@ -49,7 +49,7 @@ module Bolt
49
49
  code
50
50
  end
51
51
 
52
- targets = inventory.get_targets(targets)
52
+ targets = inventory.get_targets(targets, ext_glob: true)
53
53
 
54
54
  Puppet[:tasks] = false
55
55
  ast = pal.parse_manifest(manifest_code, manifest)
@@ -90,7 +90,7 @@ module Bolt
90
90
  # @return [Bolt::ResultSet]
91
91
  #
92
92
  def run_command(command, targets, env_vars: nil)
93
- targets = inventory.get_targets(targets)
93
+ targets = inventory.get_targets(targets, ext_glob: true)
94
94
 
95
95
  with_benchmark do
96
96
  executor.run_command(targets, command, env_vars: env_vars)
@@ -106,7 +106,7 @@ module Bolt
106
106
  #
107
107
  def download_file(source, destination, targets)
108
108
  destination = File.expand_path(destination, Dir.pwd)
109
- targets = inventory.get_targets(targets)
109
+ targets = inventory.get_targets(targets, ext_glob: true)
110
110
 
111
111
  with_benchmark do
112
112
  executor.download_file(targets, source, destination)
@@ -122,7 +122,7 @@ module Bolt
122
122
  #
123
123
  def upload_file(source, destination, targets)
124
124
  source = find_file(source)
125
- targets = inventory.get_targets(targets)
125
+ targets = inventory.get_targets(targets, ext_glob: true)
126
126
 
127
127
  Bolt::Util.validate_file('source file', source, true)
128
128
 
@@ -225,7 +225,7 @@ module Bolt
225
225
 
226
226
  with_benchmark do
227
227
  pal.lookup(key,
228
- inventory.get_targets(targets),
228
+ inventory.get_targets(targets, ext_glob: true),
229
229
  inventory,
230
230
  executor,
231
231
  plan_vars: vars)
@@ -351,6 +351,7 @@ module Bolt
351
351
  # @return [Bolt::PlanResult]
352
352
  #
353
353
  def run_plan(plan, targets, params: {})
354
+ plan_params = pal.get_plan_info(plan)['parameters']
354
355
  if targets && targets.any?
355
356
  if params['nodes'] || params['targets']
356
357
  key = params.include?('nodes') ? 'nodes' : 'targets'
@@ -360,7 +361,6 @@ module Bolt
360
361
  "in the JSON data passed in the --params option"
361
362
  end
362
363
 
363
- plan_params = pal.get_plan_info(plan)['parameters']
364
364
  target_param = plan_params.dig('targets', 'type') =~ /TargetSpec/
365
365
  node_param = plan_params.include?('nodes')
366
366
 
@@ -375,13 +375,17 @@ module Bolt
375
375
  end
376
376
  end
377
377
 
378
- plan_context = { plan_name: plan, params: params }
378
+ sensitive_params = params.keys.select { |param| plan_params.dig(param, 'sensitive') }
379
+
380
+ plan_context = { plan_name: plan, params: params, sensitive: sensitive_params }
379
381
 
380
382
  executor.start_plan(plan_context)
381
383
  result = pal.run_plan(plan, params, executor, inventory, plugins.puppetdb_client)
382
384
  executor.finish_plan(result)
383
385
 
384
386
  result
387
+ rescue Bolt::Error => e
388
+ Bolt::PlanResult.new(e, 'failure')
385
389
  end
386
390
 
387
391
  # Show plan information.
@@ -620,7 +624,10 @@ module Bolt
620
624
  Bolt::Util.validate_file('script', script)
621
625
 
622
626
  with_benchmark do
623
- executor.run_script(inventory.get_targets(targets), script, arguments, env_vars: env_vars)
627
+ executor.run_script(inventory.get_targets(targets, ext_glob: true),
628
+ script,
629
+ arguments,
630
+ env_vars: env_vars)
624
631
  end
625
632
  end
626
633
 
@@ -676,7 +683,7 @@ module Bolt
676
683
  # @return [Bolt::ResultSet]
677
684
  #
678
685
  def run_task(task, targets, params: {})
679
- targets = inventory.get_targets(targets)
686
+ targets = inventory.get_targets(targets, ext_glob: true)
680
687
 
681
688
  with_benchmark do
682
689
  pal.run_task(task, targets, params, executor, inventory)
@@ -775,7 +782,7 @@ module Bolt
775
782
  # Retrieve the known group and target names. This needs to be done before
776
783
  # updating targets, as that will add adhoc targets to the inventory.
777
784
  known_names = inventory.target_names
778
- targets = inventory.get_targets(targets)
785
+ targets = inventory.get_targets(targets, ext_glob: true)
779
786
 
780
787
  inventory_targets, adhoc_targets = targets.partition do |target|
781
788
  known_names.include?(target.name)
@@ -162,7 +162,13 @@ module Bolt
162
162
 
163
163
  def validate_hiera_config(hiera_config)
164
164
  if File.exist?(File.path(hiera_config))
165
- data = File.open(File.path(hiera_config), "r:UTF-8") { |f| YAML.safe_load(f.read, [Symbol]) }
165
+ data = File.open(File.path(hiera_config), "r:UTF-8") do |f|
166
+ if Psych.method(:safe_load).parameters.rassoc(:permitted_classes)
167
+ YAML.safe_load(f.read, permitted_classes: [Symbol])
168
+ else
169
+ YAML.safe_load(f.read, [Symbol])
170
+ end
171
+ end
166
172
  if data.nil?
167
173
  return nil
168
174
  elsif data['version'] != 5
@@ -219,7 +225,7 @@ module Bolt
219
225
  code_ast: ast,
220
226
  modulepath: @modulepath,
221
227
  project: @project.to_h,
222
- pdb_config: @pdb_client.config.to_hash,
228
+ pdb_config: @pdb_client.instance(options[:puppetdb]).config.to_hash,
223
229
  hiera_config: @hiera_config,
224
230
  plan_vars: plan_vars,
225
231
  # This data isn't available on the target config hash
@@ -10,7 +10,7 @@ module Bolt
10
10
  OPTIONS = { inventory: %w[targets query rerun],
11
11
  authentication: %w[user password password-prompt private-key host-key-check ssl ssl-verify],
12
12
  escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
13
- run_context: %w[concurrency inventoryfile save-rerun cleanup],
13
+ run_context: %w[concurrency inventoryfile save-rerun cleanup puppetdb],
14
14
  global_config_setters: PROJECT_PATHS + %w[modulepath],
15
15
  transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
16
16
  display: %w[format color verbose trace stream],
@@ -1054,6 +1054,9 @@ module Bolt
1054
1054
  define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
1055
1055
  @options[:'save-rerun'] = save
1056
1056
  end
1057
+ define('--puppetdb INSTANCE', 'The named PuppetDB instance to connect to by default.') do |instance|
1058
+ @options[:default_puppetdb] = instance
1059
+ end
1057
1060
 
1058
1061
  separator "\n#{self.class.colorize(:cyan, 'Remote environment options')}"
1059
1062
  define('--env-var ENVIRONMENT_VARIABLES', 'Environment variables to set on the target.') do |envvar|
data/lib/bolt/catalog.rb CHANGED
@@ -56,7 +56,7 @@ module Bolt
56
56
  end
57
57
 
58
58
  def compile_catalog(request)
59
- pdb_client = Bolt::PuppetDB::Client.new(Bolt::PuppetDB::Config.new(request['pdb_config']))
59
+ pdb_client = Bolt::PuppetDB::Client.new(config: request['pdb_config'])
60
60
  project = request['project']
61
61
  bolt_project = Struct.new(:name, :path, :load_as_module?).new(project['name'],
62
62
  project['path'],
@@ -54,6 +54,58 @@ module Bolt
54
54
  }
55
55
  }.freeze
56
56
 
57
+ # PuppetDB options.
58
+ PUPPETDB_OPTIONS = {
59
+ "cacert" => {
60
+ description: "The path to the ca certificate for PuppetDB.",
61
+ type: String,
62
+ _example: "/etc/puppetlabs/puppet/ssl/certs/ca.pem",
63
+ _plugin: true
64
+ },
65
+ "cert" => {
66
+ description: "The path to the client certificate file to use for authentication.",
67
+ type: String,
68
+ _example: "/etc/puppetlabs/puppet/ssl/certs/my-host.example.com.pem",
69
+ _plugin: true
70
+ },
71
+ "connect_timeout" => {
72
+ description: "How long to wait in seconds when establishing connections with PuppetDB.",
73
+ type: Integer,
74
+ minimum: 1,
75
+ _default: 60,
76
+ _example: 120,
77
+ _plugin: true
78
+ },
79
+ "key" => {
80
+ description: "The private key for the certificate.",
81
+ type: String,
82
+ _example: "/etc/puppetlabs/puppet/ssl/private_keys/my-host.example.com.pem",
83
+ _plugin: true
84
+ },
85
+ "read_timeout" => {
86
+ description: "How long to wait in seconds for a response from PuppetDB.",
87
+ type: Integer,
88
+ minimum: 1,
89
+ _default: 60,
90
+ _example: 120,
91
+ _plugin: true
92
+ },
93
+ "server_urls" => {
94
+ description: "An array containing the PuppetDB host to connect to. Include the protocol `https` "\
95
+ "and the port, which is usually `8081`. For example, "\
96
+ "`https://my-puppetdb-server.com:8081`.",
97
+ type: Array,
98
+ _example: ["https://puppet.example.com:8081"],
99
+ _plugin: true
100
+ },
101
+ "token" => {
102
+ description: "The path to the PE RBAC Token.",
103
+ type: String,
104
+ _example: "~/.puppetlabs/token",
105
+ _plugin: true
106
+ }
107
+ }.freeze
108
+
57
109
  # Definitions used to validate config options.
58
110
  # https://github.com/puppetlabs/bolt/blob/main/schemas/README.md
59
111
  OPTIONS = {
@@ -409,55 +461,17 @@ module Bolt
409
461
  description: "A map containing options for [configuring the Bolt PuppetDB "\
410
462
  "client](bolt_connect_puppetdb.md).",
411
463
  type: Hash,
412
- properties: {
413
- "cacert" => {
414
- description: "The path to the ca certificate for PuppetDB.",
415
- type: String,
416
- _example: "/etc/puppetlabs/puppet/ssl/certs/ca.pem",
417
- _plugin: true
418
- },
419
- "cert" => {
420
- description: "The path to the client certificate file to use for authentication.",
421
- type: String,
422
- _example: "/etc/puppetlabs/puppet/ssl/certs/my-host.example.com.pem",
423
- _plugin: true
424
- },
425
- "connect_timeout" => {
426
- description: "How long to wait in seconds when establishing connections with PuppetDB.",
427
- type: Integer,
428
- minimum: 1,
429
- _default: 60,
430
- _example: 120,
431
- _plugin: true
432
- },
433
- "key" => {
434
- description: "The private key for the certificate.",
435
- type: String,
436
- _example: "/etc/puppetlabs/puppet/ssl/private_keys/my-host.example.com.pem",
437
- _plugin: true
438
- },
439
- "read_timeout" => {
440
- description: "How long to wait in seconds for a response from PuppetDB.",
441
- type: Integer,
442
- minimum: 1,
443
- _default: 60,
444
- _example: 120,
445
- _plugin: true
446
- },
447
- "server_urls" => {
448
- description: "An array containing the PuppetDB host to connect to. Include the protocol `https` "\
449
- "and the port, which is usually `8081`. For example, "\
450
- "`https://my-puppetdb-server.com:8081`.",
451
- type: Array,
452
- _example: ["https://puppet.example.com:8081"],
453
- _plugin: true
454
- },
455
- "token" => {
456
- description: "The path to the PE RBAC Token.",
457
- type: String,
458
- _example: "~/.puppetlabs/token",
459
- _plugin: true
460
- }
464
+ properties: PUPPETDB_OPTIONS,
465
+ _plugin: true
466
+ },
467
+ "puppetdb-instances" => {
468
+ description: "A map of named PuppetDB instances and their configuration, where keys are the name "\
469
+ "of a PuppetDB instance and values are maps of configuration options. For more "\
470
+ "information, see [Connecting Bolt to PuppetDB](bolt_connect_puppetdb.md).",
471
+ type: Hash,
472
+ additionalProperties: {
473
+ type: Hash,
474
+ properties: PUPPETDB_OPTIONS
461
475
  },
462
476
  _plugin: true
463
477
  },
@@ -610,6 +624,7 @@ module Bolt
610
624
  plugin-hooks
611
625
  plugins
612
626
  puppetdb
627
+ puppetdb-instances
613
628
  save-rerun
614
629
  spinner
615
630
  stream
@@ -637,6 +652,7 @@ module Bolt
637
652
  plugins
638
653
  policies
639
654
  puppetdb
655
+ puppetdb-instances
640
656
  rerunfile
641
657
  save-rerun
642
658
  spinner
@@ -10,6 +10,7 @@ module Bolt
10
10
  WINDOWS_OPTIONS = %w[
11
11
  bundled-ruby
12
12
  cleanup
13
+ extensions
13
14
  interpreters
14
15
  tmpdir
15
16
  ].freeze