bolt 2.32.0 → 2.33.1

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +5 -5
  3. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +1 -1
  7. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +1 -1
  8. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +1 -1
  9. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +1 -1
  10. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
  11. data/guides/logging.txt +18 -0
  12. data/lib/bolt/config/transport/options.rb +1 -1
  13. data/lib/bolt/error.rb +4 -0
  14. data/lib/bolt/executor.rb +12 -12
  15. data/lib/bolt/module_installer.rb +1 -0
  16. data/lib/bolt/pal.rb +30 -24
  17. data/lib/bolt/pal/yaml_plan.rb +4 -2
  18. data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
  19. data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
  20. data/lib/bolt/result.rb +23 -11
  21. data/lib/bolt/shell/bash.rb +11 -6
  22. data/lib/bolt/shell/powershell.rb +11 -6
  23. data/lib/bolt/transport/base.rb +18 -18
  24. data/lib/bolt/transport/docker.rb +23 -6
  25. data/lib/bolt/transport/orch.rb +23 -14
  26. data/lib/bolt/transport/remote.rb +2 -2
  27. data/lib/bolt/transport/simple.rb +6 -6
  28. data/lib/bolt/version.rb +1 -1
  29. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
  30. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
  31. data/lib/bolt_spec/plans/mock_executor.rb +5 -5
  32. metadata +3 -3
  33. data/modules/secure_env_vars/plans/init.pp +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b010e9146d3269d88005be58db6b788f57ea3046f96f28756641b0c7266eec2
4
- data.tar.gz: ce8d15031143acabc664a7025ef004c69211c25316f9691783388ba74e61dec9
3
+ metadata.gz: cf27b6c8b1a7e3cfb2eb61617bd7ab4927161c577df4915d959182fd8bce7eaf
4
+ data.tar.gz: '05578a39ce18d1d63bf9455c8890e1e328bdcb3f52dacc3d6d5047251bca833e'
5
5
  SHA512:
6
- metadata.gz: b45657eb2b985f8e97c59ff4603ad049fd17ee6585292463a57bde3b5c7ca55451883b5e88cb0f61e55c05f1d5415cbde3874320ae446124d646a3d3e8ffa812
7
- data.tar.gz: 673e3f3310bf4f22602153bf8300851fa3a832db8e73abc9352874bea7c0b1fd50a5baa42d18474885caea7ec9fad4aa50c25f44aa27974097e10ea03b31e07e
6
+ metadata.gz: 11b3fad81f576fa435b570b15ee7cbab14b7c099b4b179770eb20dbc7f2a2db9b2d2de6c4a52eb09021a9794d13c4da704eb3a2ed362cfd50ab1946e7ef5998d
7
+ data.tar.gz: 300b9fa2214a66d239218b7a8c12518a97c2cf2fafd401c860a3ff9cdd439355608b30d72d5a82f157eea842a25a7c5bc9d484dd9f616837ebfe4beff26c0795
data/Puppetfile CHANGED
@@ -6,16 +6,16 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
6
6
 
7
7
  # Core modules used by 'apply'
8
8
  mod 'puppetlabs-service', '1.3.0'
9
- mod 'puppetlabs-puppet_agent', '4.1.1'
9
+ mod 'puppetlabs-puppet_agent', '4.2.0'
10
10
  mod 'puppetlabs-facts', '1.1.0'
11
11
 
12
12
  # Core types and providers for Puppet 6
13
13
  mod 'puppetlabs-augeas_core', '1.1.1'
14
14
  mod 'puppetlabs-host_core', '1.0.3'
15
15
  mod 'puppetlabs-scheduled_task', '2.2.1'
16
- mod 'puppetlabs-sshkeys_core', '2.1.0'
17
- mod 'puppetlabs-zfs_core', '1.1.0'
18
- mod 'puppetlabs-cron_core', '1.0.4'
16
+ mod 'puppetlabs-sshkeys_core', '2.2.0'
17
+ mod 'puppetlabs-zfs_core', '1.2.0'
18
+ mod 'puppetlabs-cron_core', '1.0.5'
19
19
  mod 'puppetlabs-mount_core', '1.0.4'
20
20
  mod 'puppetlabs-selinux_core', '1.0.4'
21
21
  mod 'puppetlabs-yumrepo_core', '1.0.7'
@@ -36,6 +36,7 @@ mod 'puppetlabs-azure_inventory', '0.4.1'
36
36
  mod 'puppetlabs-gcloud_inventory', '0.1.3'
37
37
  mod 'puppetlabs-http_request', '0.2.0'
38
38
  mod 'puppetlabs-pkcs7', '0.1.1'
39
+ mod 'puppetlabs-secure_env_vars', '0.1.0'
39
40
  mod 'puppetlabs-terraform', '0.5.0'
40
41
  mod 'puppetlabs-vault', '0.3.0'
41
42
  mod 'puppetlabs-yaml', '0.2.0'
@@ -44,4 +45,3 @@ mod 'puppetlabs-yaml', '0.2.0'
44
45
  mod 'canary', local: true
45
46
  mod 'aggregate', local: true
46
47
  mod 'puppetdb_fact', local: true
47
- mod 'secure_env_vars', local: true
@@ -112,7 +112,7 @@ Puppet::Functions.create_function(:download_file, Puppet::Functions::InternalFun
112
112
  call_function('debug', "Simulating file download of '#{source}' - no targets given - no action taken")
113
113
  r = Bolt::ResultSet.new([])
114
114
  else
115
- r = executor.download_file(targets, source, destination, options)
115
+ r = executor.download_file(targets, source, destination, options, Puppet::Pops::PuppetStack.top_of_stack)
116
116
  end
117
117
 
118
118
  if !r.ok && !options[:catch_errors]
@@ -3,6 +3,12 @@
3
3
  require 'bolt/error'
4
4
 
5
5
  # Returns the facts hash for a target.
6
+ #
7
+ # Using the `facts` function does not automatically collect facts for a target,
8
+ # and will only return facts that are currently set in the inventory. To collect
9
+ # facts from a target and set them in the inventory, run the
10
+ # [facts](writing_plans.md#collect-facts-from-targets) plan or
11
+ # [puppetdb_fact](writing_plans.md#collect-facts-from-puppetdb) plan.
6
12
  Puppet::Functions.create_function(:facts) do
7
13
  # @param target A target.
8
14
  # @return The target's facts.
@@ -2,12 +2,12 @@
2
2
 
3
3
  require 'bolt/error'
4
4
 
5
- # Makes a query to {https://puppet.com/docs/puppetdb/latest/index.html puppetdb}
5
+ # Makes a query to [puppetdb](https://puppet.com/docs/puppetdb/latest/index.html)
6
6
  # using Bolt's PuppetDB client.
7
7
  Puppet::Functions.create_function(:puppetdb_query) do
8
8
  # rubocop:disable Layout/LineLength
9
9
  # @param query A PQL query.
10
- # {https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html Learn more about Puppet's query language, PQL}
10
+ # Learn more about [Puppet's query language](https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html), PQL.
11
11
  # @return Results of the PuppetDB query.
12
12
  # @example Request certnames for all nodes
13
13
  # puppetdb_query('nodes[certname] {}')
@@ -69,7 +69,7 @@ Puppet::Functions.create_function(:run_command) do
69
69
  call_function('debug', "Simulating run_command('#{command}') - no targets given - no action taken")
70
70
  r = Bolt::ResultSet.new([])
71
71
  else
72
- r = executor.run_command(targets, command, options)
72
+ r = executor.run_command(targets, command, options, Puppet::Pops::PuppetStack.top_of_stack)
73
73
  end
74
74
 
75
75
  if !r.ok && !options[:catch_errors]
@@ -87,7 +87,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
87
87
  r = if targets.empty?
88
88
  Bolt::ResultSet.new([])
89
89
  else
90
- executor.run_script(targets, found, arguments, options)
90
+ executor.run_script(targets, found, arguments, options, Puppet::Pops::PuppetStack.top_of_stack)
91
91
  end
92
92
 
93
93
  if !r.ok && !options[:catch_errors]
@@ -133,7 +133,7 @@ Puppet::Functions.create_function(:run_task) do
133
133
  if targets.empty?
134
134
  Bolt::ResultSet.new([])
135
135
  else
136
- result = executor.run_task(targets, task, params, options)
136
+ result = executor.run_task(targets, task, params, options, Puppet::Pops::PuppetStack.top_of_stack)
137
137
  if !result.ok && !options[:catch_errors]
138
138
  raise Bolt::RunFailure.new(result, 'run_task', task_name)
139
139
  end
@@ -180,7 +180,7 @@ Puppet::Functions.create_function(:run_task_with) do
180
180
  else
181
181
  # Combine the results from the task run with any failing results that were
182
182
  # generated earlier when creating the target mapping
183
- task_result = executor.run_task_with(target_mapping, task, options)
183
+ task_result = executor.run_task_with(target_mapping, task, options, Puppet::Pops::PuppetStack.top_of_stack)
184
184
  result = Bolt::ResultSet.new(task_result.results + error_set)
185
185
 
186
186
  if !result.ok && !options[:catch_errors]
@@ -83,7 +83,7 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
83
83
  call_function('debug', "Simulating file upload of '#{found}' - no targets given - no action taken")
84
84
  r = Bolt::ResultSet.new([])
85
85
  else
86
- r = executor.upload_file(targets, found, destination, options)
86
+ r = executor.upload_file(targets, found, destination, options, Puppet::Pops::PuppetStack.top_of_stack)
87
87
  end
88
88
 
89
89
  if !r.ok && !options[:catch_errors]
@@ -0,0 +1,18 @@
1
+ TOPIC
2
+ logging
3
+
4
+ DESCRIPTION
5
+ Bolt prints messages both to the console and to log files. Messages can
6
+ either come from Bolt's 'outputter', which logs user-facing messages like
7
+ progress and results, or from the 'logger', which logs warnings, errors, and
8
+ log-structured output to log files. Both of these message streams are
9
+ configurable.
10
+
11
+ By default, Bolt logs to the console at 'warn' level and writes a log file to
12
+ '<project>/bolt-debug.log' at 'debug' level. Unless you are running a plan,
13
+ Bolt runs in verbose mode by default.
14
+
15
+ To learn more about projects, see the 'project' guide.
16
+
17
+ DOCUMENTATION
18
+ https://pup.pt/bolt-logging
@@ -357,7 +357,7 @@ module Bolt
357
357
  description: "The URL of the host used for API requests.",
358
358
  format: "uri",
359
359
  _plugin: true,
360
- _example: "https://api.example.com"
360
+ _example: "https://api.example.com:<port>"
361
361
  },
362
362
  "shell-command" => {
363
363
  type: String,
@@ -24,6 +24,10 @@ module Bolt
24
24
  h
25
25
  end
26
26
 
27
+ def add_filelineno(details)
28
+ @details.merge!(details) unless @details['file']
29
+ end
30
+
27
31
  def to_json(opts = nil)
28
32
  to_h.to_json(opts)
29
33
  end
@@ -253,33 +253,33 @@ module Bolt
253
253
  result
254
254
  end
255
255
 
256
- def run_command(targets, command, options = {})
256
+ def run_command(targets, command, options = {}, position = [])
257
257
  description = options.fetch(:description, "command '#{command}'")
258
258
  log_action(description, targets) do
259
259
  options[:run_as] = run_as if run_as && !options.key?(:run_as)
260
260
 
261
261
  batch_execute(targets) do |transport, batch|
262
262
  with_node_logging("Running command '#{command}'", batch) do
263
- transport.batch_command(batch, command, options, &method(:publish_event))
263
+ transport.batch_command(batch, command, options, position, &method(:publish_event))
264
264
  end
265
265
  end
266
266
  end
267
267
  end
268
268
 
269
- def run_script(targets, script, arguments, options = {})
269
+ def run_script(targets, script, arguments, options = {}, position = [])
270
270
  description = options.fetch(:description, "script #{script}")
271
271
  log_action(description, targets) do
272
272
  options[:run_as] = run_as if run_as && !options.key?(:run_as)
273
273
 
274
274
  batch_execute(targets) do |transport, batch|
275
275
  with_node_logging("Running script #{script} with '#{arguments.to_json}'", batch) do
276
- transport.batch_script(batch, script, arguments, options, &method(:publish_event))
276
+ transport.batch_script(batch, script, arguments, options, position, &method(:publish_event))
277
277
  end
278
278
  end
279
279
  end
280
280
  end
281
281
 
282
- def run_task(targets, task, arguments, options = {})
282
+ def run_task(targets, task, arguments, options = {}, position = [])
283
283
  description = options.fetch(:description, "task #{task.name}")
284
284
  log_action(description, targets) do
285
285
  options[:run_as] = run_as if run_as && !options.key?(:run_as)
@@ -287,13 +287,13 @@ module Bolt
287
287
 
288
288
  batch_execute(targets) do |transport, batch|
289
289
  with_node_logging("Running task #{task.name} with '#{arguments.to_json}'", batch) do
290
- transport.batch_task(batch, task, arguments, options, &method(:publish_event))
290
+ transport.batch_task(batch, task, arguments, options, position, &method(:publish_event))
291
291
  end
292
292
  end
293
293
  end
294
294
  end
295
295
 
296
- def run_task_with(target_mapping, task, options = {})
296
+ def run_task_with(target_mapping, task, options = {}, position = [])
297
297
  targets = target_mapping.keys
298
298
  description = options.fetch(:description, "task #{task.name}")
299
299
 
@@ -303,26 +303,26 @@ module Bolt
303
303
 
304
304
  batch_execute(targets) do |transport, batch|
305
305
  with_node_logging("Running task #{task.name}'", batch) do
306
- transport.batch_task_with(batch, task, target_mapping, options, &method(:publish_event))
306
+ transport.batch_task_with(batch, task, target_mapping, options, position, &method(:publish_event))
307
307
  end
308
308
  end
309
309
  end
310
310
  end
311
311
 
312
- def upload_file(targets, source, destination, options = {})
312
+ def upload_file(targets, source, destination, options = {}, position = [])
313
313
  description = options.fetch(:description, "file upload from #{source} to #{destination}")
314
314
  log_action(description, targets) do
315
315
  options[:run_as] = run_as if run_as && !options.key?(:run_as)
316
316
 
317
317
  batch_execute(targets) do |transport, batch|
318
318
  with_node_logging("Uploading file #{source} to #{destination}", batch) do
319
- transport.batch_upload(batch, source, destination, options, &method(:publish_event))
319
+ transport.batch_upload(batch, source, destination, options, position, &method(:publish_event))
320
320
  end
321
321
  end
322
322
  end
323
323
  end
324
324
 
325
- def download_file(targets, source, destination, options = {})
325
+ def download_file(targets, source, destination, options = {}, position = [])
326
326
  description = options.fetch(:description, "file download from #{source} to #{destination}")
327
327
 
328
328
  begin
@@ -337,7 +337,7 @@ module Bolt
337
337
 
338
338
  batch_execute(targets) do |transport, batch|
339
339
  with_node_logging("Downloading file #{source} to #{destination}", batch) do
340
- transport.batch_download(batch, source, destination, options, &method(:publish_event))
340
+ transport.batch_download(batch, source, destination, options, position, &method(:publish_event))
341
341
  end
342
342
  end
343
343
  end
@@ -187,6 +187,7 @@ module Bolt
187
187
  ok = Installer.new(config).install(path, moduledir)
188
188
 
189
189
  # Automatically generate types after installing modules
190
+ @outputter.print_action_step("Generating type references")
190
191
  @pal.generate_types
191
192
 
192
193
  @outputter.print_puppetfile_result(ok, path, moduledir)
@@ -14,17 +14,11 @@ module Bolt
14
14
  # Bolt::Errors
15
15
  class PALError < Bolt::Error
16
16
  def self.from_preformatted_error(err)
17
- if err.cause.is_a? Bolt::Error
18
- err.cause
19
- else
20
- from_error(err)
21
- end
22
- end
23
-
24
- # Generate a Bolt::Pal::PALError for non-bolt errors
25
- def self.from_error(err)
26
- # Use the original error message if available
27
- message = err.cause ? err.cause.message : err.message
17
+ error = if err.cause.is_a? Bolt::Error
18
+ err.cause
19
+ else
20
+ from_error(err)
21
+ end
28
22
 
29
23
  # Provide the location of an error if it came from a plan
30
24
  details = {}
@@ -32,8 +26,15 @@ module Bolt
32
26
  details[:line] = err.line if defined?(err.line)
33
27
  details[:column] = err.pos if defined?(err.pos)
34
28
 
35
- e = new(message, details.compact)
29
+ error.add_filelineno(details)
30
+ error
31
+ end
36
32
 
33
+ # Generate a Bolt::Pal::PALError for non-bolt errors
34
+ def self.from_error(err)
35
+ # Use the original error message if available
36
+ message = err.cause ? err.cause.message : err.message
37
+ e = new(message)
37
38
  e.set_backtrace(err.backtrace)
38
39
  e
39
40
  end
@@ -256,19 +257,24 @@ module Bolt
256
257
 
257
258
  # TODO: PUP-8553 should replace this
258
259
  def with_puppet_settings
259
- Dir.mktmpdir('bolt') do |dir|
260
- cli = []
261
- Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
262
- cli << "--#{setting}" << dir
263
- end
264
- Puppet.settings.send(:clear_everything_for_tests)
265
- Puppet.initialize_settings(cli)
266
- Puppet::GettextConfig.create_default_text_domain
267
- Puppet[:trusted_external_command] = @trusted_external
268
- Puppet.settings[:hiera_config] = @hiera_config
269
- self.class.configure_logging
270
- yield
260
+ dir = Dir.mktmpdir('bolt')
261
+
262
+ cli = []
263
+ Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
264
+ cli << "--#{setting}" << dir
271
265
  end
266
+ Puppet.settings.send(:clear_everything_for_tests)
267
+ Puppet.initialize_settings(cli)
268
+ Puppet::GettextConfig.create_default_text_domain
269
+ Puppet[:trusted_external_command] = @trusted_external
270
+ Puppet.settings[:hiera_config] = @hiera_config
271
+ self.class.configure_logging
272
+ yield
273
+ ensure
274
+ # Delete the tmpdir if it still exists. This check is needed to
275
+ # prevent Bolt from erroring if the tmpdir is somehow deleted
276
+ # before reaching this point.
277
+ FileUtils.remove_entry_secure(dir) if File.exist?(dir)
272
278
  end
273
279
 
274
280
  # Parses a snippet of Puppet manifest code and returns the AST represented
@@ -98,10 +98,12 @@ module Bolt
98
98
  # subclasses this parent class in order to implement its own evaluation
99
99
  # logic.
100
100
  class EvaluableString
101
- attr_reader :value
101
+ attr_reader :file, :line, :value
102
102
 
103
- def initialize(value)
103
+ def initialize(value, file = nil, line = nil)
104
104
  @value = value
105
+ @file = file
106
+ @line = line
105
107
  end
106
108
 
107
109
  def ==(other)
@@ -191,7 +191,11 @@ module Bolt
191
191
  o[key] = evaluate_code_blocks(scope, v)
192
192
  end
193
193
  when EvaluableString
194
- value.evaluate(scope, @evaluator)
194
+ begin
195
+ value.evaluate(scope, @evaluator)
196
+ rescue StandardError => e
197
+ raise format_evaluate_error(e, value)
198
+ end
195
199
  else
196
200
  value
197
201
  end
@@ -203,6 +207,24 @@ module Bolt
203
207
  def evaluate(value, _scope)
204
208
  value
205
209
  end
210
+
211
+ def format_evaluate_error(error, value)
212
+ # The Puppet::PreformattedError includes the line number of the
213
+ # evaluable string that caused the error, while the value includes the
214
+ # line number of the YAML plan that the string began on. To get the
215
+ # actual line number of the error, add these two numbers together.
216
+ line = error.line + value.line
217
+
218
+ # If the evaluable string is not a scalar literal, correct for it
219
+ # being on the same line as the step key.
220
+ line -= 1 if value.is_a?(BareString)
221
+
222
+ Bolt::PlanFailure.new(
223
+ error.basic_message,
224
+ 'bolt/evaluation-error',
225
+ { file: value.file, line: line }
226
+ )
227
+ end
206
228
  end
207
229
  end
208
230
  end
@@ -9,10 +9,15 @@ module Bolt
9
9
  class YamlPlan
10
10
  class Loader
11
11
  class PuppetVisitor < Psych::Visitors::NoAliasRuby
12
- def self.create_visitor
12
+ def initialize(scanner, class_loader, file)
13
+ super(scanner, class_loader)
14
+ @file = file
15
+ end
16
+
17
+ def self.create_visitor(source_ref)
13
18
  class_loader = Psych::ClassLoader::Restricted.new([], [])
14
19
  scanner = Psych::ScalarScanner.new(class_loader)
15
- new(scanner, class_loader)
20
+ new(scanner, class_loader, source_ref)
16
21
  end
17
22
 
18
23
  def deserialize(node)
@@ -23,18 +28,18 @@ module Bolt
23
28
  # @ss is a ScalarScanner, from the base ToRuby visitor class
24
29
  node.value
25
30
  when Psych::Nodes::Scalar::DOUBLE_QUOTED
26
- DoubleQuotedString.new(node.value)
27
- # | style string or > style string
28
- when Psych::Nodes::Scalar::LITERAL, Psych::Nodes::Scalar::FOLDED
29
- CodeLiteral.new(node.value)
30
- # This one shouldn't be possible
31
+ DoubleQuotedString.new(node.value, @file, node.start_line + 1)
32
+ # | style string
33
+ when Psych::Nodes::Scalar::LITERAL
34
+ CodeLiteral.new(node.value, @file, node.start_line + 1)
35
+ # > style string
31
36
  else
32
37
  @ss.tokenize(node.value)
33
38
  end
34
39
  else
35
40
  value = @ss.tokenize(node.value)
36
41
  if value.is_a?(String)
37
- BareString.new(value)
42
+ BareString.new(value, @file, node.start_line + 1)
38
43
  else
39
44
  value
40
45
  end
@@ -50,7 +55,7 @@ module Bolt
50
55
  else
51
56
  Psych.parse(yaml_string, source_ref)
52
57
  end
53
- PuppetVisitor.create_visitor.accept(parse_tree)
58
+ PuppetVisitor.create_visitor(source_ref).accept(parse_tree)
54
59
  end
55
60
 
56
61
  def self.from_string(name, yaml_string, source_ref)
@@ -7,47 +7,58 @@ module Bolt
7
7
  class Result
8
8
  attr_reader :target, :value, :action, :object
9
9
 
10
- def self.from_exception(target, exception, action: 'action')
10
+ def self.from_exception(target, exception, action: 'action', position: [])
11
+ details = create_details(position)
11
12
  if exception.is_a?(Bolt::Error)
12
- error = exception.to_h
13
+ error = Bolt::Util.deep_merge({ 'details' => details }, exception.to_h)
13
14
  else
15
+ details['class'] = exception.class.to_s
14
16
  error = {
15
17
  'kind' => 'puppetlabs.tasks/exception-error',
16
18
  'issue_code' => 'EXCEPTION',
17
19
  'msg' => exception.message,
18
- 'details' => { 'class' => exception.class.to_s }
20
+ 'details' => details
19
21
  }
20
22
  error['details']['stack_trace'] = exception.backtrace.join('\n') if exception.backtrace
21
23
  end
22
24
  Result.new(target, error: error, action: action)
23
25
  end
24
26
 
25
- def self.for_command(target, stdout, stderr, exit_code, action, command)
27
+ def self.create_details(position)
28
+ %w[file line].zip(position).to_h.compact
29
+ end
30
+
31
+ def self.for_command(target, stdout, stderr, exit_code, action, command, position)
26
32
  value = {
27
33
  'stdout' => stdout,
28
34
  'stderr' => stderr,
29
35
  'exit_code' => exit_code
30
36
  }
37
+
38
+ details = create_details(position)
31
39
  unless exit_code == 0
40
+ details['exit_code'] = exit_code
32
41
  value['_error'] = {
33
42
  'kind' => 'puppetlabs.tasks/command-error',
34
43
  'issue_code' => 'COMMAND_ERROR',
35
44
  'msg' => "The command failed with exit code #{exit_code}",
36
- 'details' => { 'exit_code' => exit_code }
45
+ 'details' => details
37
46
  }
38
47
  end
39
48
  new(target, value: value, action: action, object: command)
40
49
  end
41
50
 
42
- def self.for_task(target, stdout, stderr, exit_code, task)
51
+ def self.for_task(target, stdout, stderr, exit_code, task, position)
43
52
  stdout.force_encoding('utf-8') unless stdout.encoding == Encoding::UTF_8
53
+
54
+ details = create_details(position)
44
55
  value = if stdout.valid_encoding?
45
56
  parse_hash(stdout) || { '_output' => stdout }
46
57
  else
47
58
  { '_error' => { 'kind' => 'puppetlabs.tasks/task-error',
48
59
  'issue_code' => 'TASK_ERROR',
49
60
  'msg' => 'The task result contained invalid UTF-8 on stdout',
50
- 'details' => {} } }
61
+ 'details' => details } }
51
62
  end
52
63
 
53
64
  if exit_code != 0 && value['_error'].nil?
@@ -60,24 +71,26 @@ module Bolt
60
71
  else
61
72
  "The task failed with exit code #{exit_code}"
62
73
  end
74
+ details['exit_code'] = exit_code
63
75
  value['_error'] = { 'kind' => 'puppetlabs.tasks/task-error',
64
76
  'issue_code' => 'TASK_ERROR',
65
77
  'msg' => msg,
66
- 'details' => { 'exit_code' => exit_code } }
78
+ 'details' => details }
67
79
  end
68
80
 
69
81
  if value.key?('_error')
70
82
  unless value['_error'].is_a?(Hash) && value['_error'].key?('msg')
83
+ details['original_error'] = value['_error']
71
84
  value['_error'] = {
72
85
  'msg' => "Invalid error returned from task #{task}: #{value['_error'].inspect}. Error "\
73
86
  "must be an object with a msg key.",
74
87
  'kind' => 'bolt/invalid-task-error',
75
- 'details' => { 'original_error' => value['_error'] }
88
+ 'details' => details
76
89
  }
77
90
  end
78
91
 
79
92
  value['_error']['kind'] ||= 'bolt/error'
80
- value['_error']['details'] ||= {}
93
+ value['_error']['details'] ||= details
81
94
  end
82
95
 
83
96
  if value.key?('_sensitive')
@@ -221,7 +234,6 @@ module Bolt
221
234
  def error
222
235
  if error_hash
223
236
  Puppet::DataTypes::Error.from_asserted_hash(error_hash)
224
-
225
237
  end
226
238
  end
227
239
 
@@ -21,14 +21,16 @@ module Bolt
21
21
  ['shell']
22
22
  end
23
23
 
24
- def run_command(command, options = {})
24
+ def run_command(command, options = {}, position = [])
25
25
  running_as(options[:run_as]) do
26
26
  output = execute(command, environment: options[:env_vars], sudoable: true)
27
27
  Bolt::Result.for_command(target,
28
28
  output.stdout.string,
29
29
  output.stderr.string,
30
30
  output.exit_code,
31
- 'command', command)
31
+ 'command',
32
+ command,
33
+ position)
32
34
  end
33
35
  end
34
36
 
@@ -71,7 +73,7 @@ module Bolt
71
73
  end
72
74
  end
73
75
 
74
- def run_script(script, arguments, options = {})
76
+ def run_script(script, arguments, options = {}, position = [])
75
77
  # unpack any Sensitive data
76
78
  arguments = unwrap_sensitive_args(arguments)
77
79
 
@@ -84,12 +86,14 @@ module Bolt
84
86
  output.stdout.string,
85
87
  output.stderr.string,
86
88
  output.exit_code,
87
- 'script', script)
89
+ 'script',
90
+ script,
91
+ position)
88
92
  end
89
93
  end
90
94
  end
91
95
 
92
- def run_task(task, arguments, options = {})
96
+ def run_task(task, arguments, options = {}, position = [])
93
97
  implementation = select_implementation(target, task)
94
98
  executable = implementation['path']
95
99
  input_method = implementation['input_method']
@@ -148,7 +152,8 @@ module Bolt
148
152
  Bolt::Result.for_task(target, output.stdout.string,
149
153
  output.stderr.string,
150
154
  output.exit_code,
151
- task.name)
155
+ task.name,
156
+ position)
152
157
  end
153
158
  end
154
159
 
@@ -174,7 +174,7 @@ module Bolt
174
174
  Bolt::Result.for_download(target, source, destination, download)
175
175
  end
176
176
 
177
- def run_command(command, options = {})
177
+ def run_command(command, options = {}, position = [])
178
178
  command = [*env_declarations(options[:env_vars]), command].join("\r\n") if options[:env_vars]
179
179
 
180
180
  output = execute(command)
@@ -182,10 +182,12 @@ module Bolt
182
182
  output.stdout.string,
183
183
  output.stderr.string,
184
184
  output.exit_code,
185
- 'command', command)
185
+ 'command',
186
+ command,
187
+ position)
186
188
  end
187
189
 
188
- def run_script(script, arguments, options = {})
190
+ def run_script(script, arguments, options = {}, position = [])
189
191
  # unpack any Sensitive data
190
192
  arguments = unwrap_sensitive_args(arguments)
191
193
  with_tmpdir do |dir|
@@ -204,11 +206,13 @@ module Bolt
204
206
  output.stdout.string,
205
207
  output.stderr.string,
206
208
  output.exit_code,
207
- 'script', script)
209
+ 'script',
210
+ script,
211
+ position)
208
212
  end
209
213
  end
210
214
 
211
- def run_task(task, arguments, _options = {})
215
+ def run_task(task, arguments, _options = {}, position = [])
212
216
  implementation = select_implementation(target, task)
213
217
  executable = implementation['path']
214
218
  input_method = implementation['input_method']
@@ -259,7 +263,8 @@ module Bolt
259
263
  Bolt::Result.for_task(target, output.stdout.string,
260
264
  output.stderr.string,
261
265
  output.exit_code,
262
- task.name)
266
+ task.name,
267
+ position)
263
268
  end
264
269
  end
265
270
 
@@ -43,13 +43,13 @@ module Bolt
43
43
  @logger = Bolt::Logger.logger(self)
44
44
  end
45
45
 
46
- def with_events(target, callback, action)
46
+ def with_events(target, callback, action, position)
47
47
  callback&.call(type: :node_start, target: target)
48
48
 
49
49
  result = begin
50
50
  yield
51
51
  rescue StandardError, NotImplementedError => e
52
- Bolt::Result.from_exception(target, e, action: action)
52
+ Bolt::Result.from_exception(target, e, action: action, position: position)
53
53
  end
54
54
 
55
55
  callback&.call(type: :node_result, result: result)
@@ -100,12 +100,12 @@ module Bolt
100
100
  # The default implementation only supports batches of size 1 and will fail otherwise.
101
101
  #
102
102
  # Transports may override this method to implement their own batch processing.
103
- def batch_task(targets, task, arguments, options = {}, &callback)
103
+ def batch_task(targets, task, arguments, options = {}, position = [], &callback)
104
104
  assert_batch_size_one("batch_task()", targets)
105
105
  target = targets.first
106
- with_events(target, callback, 'task') do
106
+ with_events(target, callback, 'task', position) do
107
107
  @logger.debug { "Running task '#{task.name}' on #{target.safe_name}" }
108
- run_task(target, task, arguments, options)
108
+ run_task(target, task, arguments, options, position)
109
109
  end
110
110
  end
111
111
 
@@ -114,14 +114,14 @@ module Bolt
114
114
  # The default implementation only supports batches of size 1 and will fail otherwise.
115
115
  #
116
116
  # Transports may override this method to implment their own batch processing.
117
- def batch_task_with(targets, task, target_mapping, options = {}, &callback)
117
+ def batch_task_with(targets, task, target_mapping, options = {}, position = [], &callback)
118
118
  assert_batch_size_one("batch_task_with()", targets)
119
119
  target = targets.first
120
120
  arguments = target_mapping[target]
121
121
 
122
- with_events(target, callback, 'task') do
122
+ with_events(target, callback, 'task', position) do
123
123
  @logger.debug { "Running task '#{task.name}' on #{target.safe_name} with '#{arguments.to_json}'" }
124
- run_task(target, task, arguments, options)
124
+ run_task(target, task, arguments, options, position)
125
125
  end
126
126
  end
127
127
 
@@ -130,12 +130,12 @@ module Bolt
130
130
  # The default implementation only supports batches of size 1 and will fail otherwise.
131
131
  #
132
132
  # Transports may override this method to implement their own batch processing.
133
- def batch_command(targets, command, options = {}, &callback)
133
+ def batch_command(targets, command, options = {}, position = [], &callback)
134
134
  assert_batch_size_one("batch_command()", targets)
135
135
  target = targets.first
136
- with_events(target, callback, 'command') do
136
+ with_events(target, callback, 'command', position) do
137
137
  @logger.debug("Running command '#{command}' on #{target.safe_name}")
138
- run_command(target, command, options)
138
+ run_command(target, command, options, position)
139
139
  end
140
140
  end
141
141
 
@@ -144,12 +144,12 @@ module Bolt
144
144
  # The default implementation only supports batches of size 1 and will fail otherwise.
145
145
  #
146
146
  # Transports may override this method to implement their own batch processing.
147
- def batch_script(targets, script, arguments, options = {}, &callback)
147
+ def batch_script(targets, script, arguments, options = {}, position = [], &callback)
148
148
  assert_batch_size_one("batch_script()", targets)
149
149
  target = targets.first
150
- with_events(target, callback, 'script') do
150
+ with_events(target, callback, 'script', position) do
151
151
  @logger.debug { "Running script '#{script}' on #{target.safe_name}" }
152
- run_script(target, script, arguments, options)
152
+ run_script(target, script, arguments, options, position)
153
153
  end
154
154
  end
155
155
 
@@ -158,10 +158,10 @@ module Bolt
158
158
  # The default implementation only supports batches of size 1 and will fail otherwise.
159
159
  #
160
160
  # Transports may override this method to implement their own batch processing.
161
- def batch_upload(targets, source, destination, options = {}, &callback)
161
+ def batch_upload(targets, source, destination, options = {}, position = [], &callback)
162
162
  assert_batch_size_one("batch_upload()", targets)
163
163
  target = targets.first
164
- with_events(target, callback, 'upload') do
164
+ with_events(target, callback, 'upload', position) do
165
165
  @logger.debug { "Uploading: '#{source}' to #{destination} on #{target.safe_name}" }
166
166
  upload(target, source, destination, options)
167
167
  end
@@ -173,12 +173,12 @@ module Bolt
173
173
  # The default implementation only supports batches of size 1 and will fail otherwise.
174
174
  #
175
175
  # Transports may override this method to implement their own batch processing.
176
- def batch_download(targets, source, destination, options = {}, &callback)
176
+ def batch_download(targets, source, destination, options = {}, position = [], &callback)
177
177
  require 'erb'
178
178
 
179
179
  assert_batch_size_one("batch_download()", targets)
180
180
  target = targets.first
181
- with_events(target, callback, 'download') do
181
+ with_events(target, callback, 'download', position) do
182
182
  escaped_name = ERB::Util.url_encode(target.safe_name)
183
183
  target_destination = File.expand_path(escaped_name, destination)
184
184
  @logger.debug { "Downloading: '#{source}' on #{target.safe_name} to #{target_destination}" }
@@ -46,7 +46,7 @@ module Bolt
46
46
  end
47
47
  end
48
48
 
49
- def run_command(target, command, options = {})
49
+ def run_command(target, command, options = {}, position = [])
50
50
  execute_options = {}
51
51
  execute_options[:tty] = target.options['tty']
52
52
  execute_options[:environment] = options[:env_vars]
@@ -58,11 +58,17 @@ module Bolt
58
58
  end
59
59
  with_connection(target) do |conn|
60
60
  stdout, stderr, exitcode = conn.execute(*Shellwords.split(command), execute_options)
61
- Bolt::Result.for_command(target, stdout, stderr, exitcode, 'command', command)
61
+ Bolt::Result.for_command(target,
62
+ stdout,
63
+ stderr,
64
+ exitcode,
65
+ 'command',
66
+ command,
67
+ position)
62
68
  end
63
69
  end
64
70
 
65
- def run_script(target, script, arguments, options = {})
71
+ def run_script(target, script, arguments, options = {}, position = [])
66
72
  # unpack any Sensitive data
67
73
  arguments = unwrap_sensitive_args(arguments)
68
74
  execute_options = {}
@@ -72,12 +78,18 @@ module Bolt
72
78
  conn.with_remote_tmpdir do |dir|
73
79
  remote_path = conn.write_remote_executable(dir, script)
74
80
  stdout, stderr, exitcode = conn.execute(remote_path, *arguments, execute_options)
75
- Bolt::Result.for_command(target, stdout, stderr, exitcode, 'script', script)
81
+ Bolt::Result.for_command(target,
82
+ stdout,
83
+ stderr,
84
+ exitcode,
85
+ 'script',
86
+ script,
87
+ position)
76
88
  end
77
89
  end
78
90
  end
79
91
 
80
- def run_task(target, task, arguments, _options = {})
92
+ def run_task(target, task, arguments, _options = {}, position = [])
81
93
  implementation = task.select_implementation(target, provided_features)
82
94
  executable = implementation['path']
83
95
  input_method = implementation['input_method']
@@ -113,7 +125,12 @@ module Bolt
113
125
  end
114
126
 
115
127
  stdout, stderr, exitcode = conn.execute(remote_task_path, execute_options)
116
- Bolt::Result.for_task(target, stdout, stderr, exitcode, task.name)
128
+ Bolt::Result.for_task(target,
129
+ stdout,
130
+ stderr,
131
+ exitcode,
132
+ task.name,
133
+ position)
117
134
  end
118
135
  end
119
136
  end
@@ -53,7 +53,7 @@ module Bolt
53
53
  conn
54
54
  end
55
55
 
56
- def process_run_results(targets, results, task_name)
56
+ def process_run_results(targets, results, task_name, position = [])
57
57
  targets_by_name = Hash[targets.map { |t| t.host || t.name }.zip(targets)]
58
58
  results.map do |node_result|
59
59
  target = targets_by_name[node_result['name']]
@@ -63,25 +63,31 @@ module Bolt
63
63
  # If it's finished or already has a proper error simply pass it to the
64
64
  # the result otherwise make sure an error is generated
65
65
  if state == 'finished' || (result && result['_error'])
66
+ if result['_error']
67
+ file_line = %w[file line].zip(position).to_h.compact
68
+ result['_error']['details'].merge!(file_line) unless result['_error']['details']['file']
69
+ end
70
+
66
71
  Bolt::Result.new(target, value: result, action: 'task', object: task_name)
67
72
  elsif state == 'skipped'
73
+ details = %w[file line].zip(position).to_h.compact
68
74
  Bolt::Result.new(
69
75
  target,
70
76
  value: { '_error' => {
71
77
  'kind' => 'puppetlabs.tasks/skipped-node',
72
78
  'msg' => "Target #{target.safe_name} was skipped",
73
- 'details' => {}
79
+ 'details' => details
74
80
  } },
75
81
  action: 'task', object: task_name
76
82
  )
77
83
  else
78
84
  # Make a generic error with a unkown exit_code
79
- Bolt::Result.for_task(target, result.to_json, '', 'unknown', task_name)
85
+ Bolt::Result.for_task(target, result.to_json, '', 'unknown', task_name, position)
80
86
  end
81
87
  end
82
88
  end
83
89
 
84
- def batch_command(targets, command, options = {}, &callback)
90
+ def batch_command(targets, command, options = {}, position = [], &callback)
85
91
  if options[:env_vars] && !options[:env_vars].empty?
86
92
  raise NotImplementedError, "pcp transport does not support setting environment variables"
87
93
  end
@@ -93,6 +99,7 @@ module Bolt
93
99
  BOLT_COMMAND_TASK,
94
100
  params,
95
101
  options,
102
+ position,
96
103
  &callback)
97
104
  callback ||= proc {}
98
105
  results.map! { |result| unwrap_bolt_result(result.target, result, 'command', command) }
@@ -101,7 +108,7 @@ module Bolt
101
108
  end
102
109
  end
103
110
 
104
- def batch_script(targets, script, arguments, options = {}, &callback)
111
+ def batch_script(targets, script, arguments, options = {}, position = [], &callback)
105
112
  if options[:env_vars] && !options[:env_vars].empty?
106
113
  raise NotImplementedError, "pcp transport does not support setting environment variables"
107
114
  end
@@ -114,7 +121,7 @@ module Bolt
114
121
  'name' => Pathname(script).basename.to_s
115
122
  }
116
123
  callback ||= proc {}
117
- results = run_task_job(targets, BOLT_SCRIPT_TASK, params, options, &callback)
124
+ results = run_task_job(targets, BOLT_SCRIPT_TASK, params, options, position, &callback)
118
125
  results.map! { |result| unwrap_bolt_result(result.target, result, 'script', script) }
119
126
  results.each do |result|
120
127
  callback.call(type: :node_result, result: result)
@@ -155,7 +162,7 @@ module Bolt
155
162
  output&.close
156
163
  end
157
164
 
158
- def batch_upload(targets, source, destination, options = {}, &callback)
165
+ def batch_upload(targets, source, destination, options = {}, position = [], &callback)
159
166
  stat = File.stat(source)
160
167
  content = if stat.directory?
161
168
  pack(source)
@@ -171,7 +178,7 @@ module Bolt
171
178
  'directory' => stat.directory?
172
179
  }
173
180
  callback ||= proc {}
174
- results = run_task_job(targets, BOLT_UPLOAD_TASK, params, options, &callback)
181
+ results = run_task_job(targets, BOLT_UPLOAD_TASK, params, options, position, &callback)
175
182
  results.map! do |result|
176
183
  if result.error_hash
177
184
  result
@@ -200,7 +207,7 @@ module Bolt
200
207
  targets.group_by { |target| Connection.get_key(target.options) }.values
201
208
  end
202
209
 
203
- def run_task_job(targets, task, arguments, options)
210
+ def run_task_job(targets, task, arguments, options, position)
204
211
  targets.each do |target|
205
212
  yield(type: :node_start, target: target) if block_given?
206
213
  end
@@ -210,7 +217,7 @@ module Bolt
210
217
  arguments = unwrap_sensitive_args(arguments)
211
218
  results = get_connection(targets.first.options).run_task(targets, task, arguments, options)
212
219
 
213
- process_run_results(targets, results, task.name)
220
+ process_run_results(targets, results, task.name, position)
214
221
  rescue OrchestratorClient::ApiError => e
215
222
  targets.map do |target|
216
223
  Bolt::Result.new(target, error: e.data)
@@ -222,15 +229,15 @@ module Bolt
222
229
  end
223
230
  end
224
231
 
225
- def batch_task(targets, task, arguments, options = {}, &callback)
232
+ def batch_task(targets, task, arguments, options = {}, position = [], &callback)
226
233
  callback ||= proc {}
227
- results = run_task_job(targets, task, arguments, options, &callback)
234
+ results = run_task_job(targets, task, arguments, options, position, &callback)
228
235
  results.each do |result|
229
236
  callback.call(type: :node_result, result: result)
230
237
  end
231
238
  end
232
239
 
233
- def batch_task_with(_targets, _task, _target_mapping, _options = {})
240
+ def batch_task_with(_targets, _task, _target_mapping, _options = {}, _position = [])
234
241
  raise NotImplementedError, "pcp transport does not support run_task_with()"
235
242
  end
236
243
 
@@ -248,11 +255,13 @@ module Bolt
248
255
  return result
249
256
  end
250
257
 
258
+ # If we get here, there's no error so we don't need the file or line
259
+ # number
251
260
  Bolt::Result.for_command(target,
252
261
  result.value['stdout'],
253
262
  result.value['stderr'],
254
263
  result.value['exit_code'],
255
- action, obj)
264
+ action, obj, [])
256
265
  end
257
266
  end
258
267
  end
@@ -26,14 +26,14 @@ module Bolt
26
26
  end
27
27
 
28
28
  # Cannot batch because arugments differ
29
- def run_task(target, task, arguments, options = {})
29
+ def run_task(target, task, arguments, options = {}, position = [])
30
30
  proxy_target = get_proxy(target)
31
31
  transport = @executor.transport(proxy_target.transport)
32
32
  arguments = arguments.merge('_target' => target.to_h.reject { |_, v| v.nil? })
33
33
 
34
34
  remote_task = task.remote_instance
35
35
 
36
- result = transport.run_task(proxy_target, remote_task, arguments, options)
36
+ result = transport.run_task(proxy_target, remote_task, arguments, options, position)
37
37
  Bolt::Result.new(target, value: result.value, action: 'task', object: task.name)
38
38
  end
39
39
  end
@@ -20,9 +20,9 @@ module Bolt
20
20
  false
21
21
  end
22
22
 
23
- def run_command(target, command, options = {})
23
+ def run_command(target, command, options = {}, position = [])
24
24
  with_connection(target) do |conn|
25
- conn.shell.run_command(command, options)
25
+ conn.shell.run_command(command, options, position)
26
26
  end
27
27
  end
28
28
 
@@ -38,15 +38,15 @@ module Bolt
38
38
  end
39
39
  end
40
40
 
41
- def run_script(target, script, arguments, options = {})
41
+ def run_script(target, script, arguments, options = {}, position = [])
42
42
  with_connection(target) do |conn|
43
- conn.shell.run_script(script, arguments, options)
43
+ conn.shell.run_script(script, arguments, options, position)
44
44
  end
45
45
  end
46
46
 
47
- def run_task(target, task, arguments, options = {})
47
+ def run_task(target, task, arguments, options = {}, position = [])
48
48
  with_connection(target) do |conn|
49
- conn.shell.run_task(task, arguments, options)
49
+ conn.shell.run_task(task, arguments, options, position)
50
50
  end
51
51
  end
52
52
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '2.32.0'
4
+ VERSION = '2.33.1'
5
5
  end
@@ -29,7 +29,7 @@ module BoltSpec
29
29
  end
30
30
 
31
31
  def result_for(target, stdout: '', stderr: '')
32
- Bolt::Result.for_command(target, stdout, stderr, 0, 'command', '')
32
+ Bolt::Result.for_command(target, stdout, stderr, 0, 'command', '', [])
33
33
  end
34
34
 
35
35
  # Public methods
@@ -35,7 +35,7 @@ module BoltSpec
35
35
  end
36
36
 
37
37
  def result_for(target, stdout: '', stderr: '')
38
- Bolt::Result.for_command(target, stdout, stderr, 0, 'script', '')
38
+ Bolt::Result.for_command(target, stdout, stderr, 0, 'script', '', [])
39
39
  end
40
40
 
41
41
  # Public methods
@@ -48,7 +48,7 @@ module BoltSpec
48
48
  ([segments[0]] + segments[2..-1]).join('/')
49
49
  end
50
50
 
51
- def run_command(targets, command, options = {})
51
+ def run_command(targets, command, options = {}, _position = [])
52
52
  result = nil
53
53
  if (doub = @command_doubles[command] || @command_doubles[:default])
54
54
  result = doub.process(targets, command, options)
@@ -61,7 +61,7 @@ module BoltSpec
61
61
  result
62
62
  end
63
63
 
64
- def run_script(targets, script_path, arguments, options = {})
64
+ def run_script(targets, script_path, arguments, options = {}, _position = [])
65
65
  script = module_file_id(script_path)
66
66
  result = nil
67
67
  if (doub = @script_doubles[script] || @script_doubles[:default])
@@ -76,7 +76,7 @@ module BoltSpec
76
76
  result
77
77
  end
78
78
 
79
- def run_task(targets, task, arguments, options = {})
79
+ def run_task(targets, task, arguments, options = {}, _position = [])
80
80
  result = nil
81
81
  if (doub = @task_doubles[task.name] || @task_doubles[:default])
82
82
  result = doub.process(targets, task.name, arguments, options)
@@ -90,7 +90,7 @@ module BoltSpec
90
90
  result
91
91
  end
92
92
 
93
- def download_file(targets, source, destination, options = {})
93
+ def download_file(targets, source, destination, options = {}, _position = [])
94
94
  result = nil
95
95
  if (doub = @download_doubles[source] || @download_doubles[:default])
96
96
  result = doub.process(targets, source, destination, options)
@@ -103,7 +103,7 @@ module BoltSpec
103
103
  result
104
104
  end
105
105
 
106
- def upload_file(targets, source_path, destination, options = {})
106
+ def upload_file(targets, source_path, destination, options = {}, _position = [])
107
107
  source = module_file_id(source_path)
108
108
  result = nil
109
109
  if (doub = @upload_doubles[source] || @upload_doubles[:default])
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: 2.32.0
4
+ version: 2.33.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-26 00:00:00.000000000 Z
11
+ date: 2020-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -438,6 +438,7 @@ files:
438
438
  - bolt-modules/system/lib/puppet/functions/system/env.rb
439
439
  - exe/bolt
440
440
  - guides/inventory.txt
441
+ - guides/logging.txt
441
442
  - guides/module.txt
442
443
  - guides/modulepath.txt
443
444
  - guides/project.txt
@@ -597,7 +598,6 @@ files:
597
598
  - modules/canary/lib/puppet/functions/canary/skip.rb
598
599
  - modules/canary/plans/init.pp
599
600
  - modules/puppetdb_fact/plans/init.pp
600
- - modules/secure_env_vars/plans/init.pp
601
601
  homepage: https://github.com/puppetlabs/bolt
602
602
  licenses:
603
603
  - Apache-2.0
@@ -1,20 +0,0 @@
1
- plan secure_env_vars(
2
- TargetSpec $targets,
3
- Optional[String] $command = undef,
4
- Optional[String] $script = undef
5
- ) {
6
- $env_vars = parsejson(system::env('BOLT_ENV_VARS'))
7
- unless type($command) == Undef or type($script) == Undef {
8
- fail_plan('Cannot specify both script and command for secure_env_vars')
9
- }
10
-
11
- return if $command {
12
- run_command($command, $targets, '_env_vars' => $env_vars)
13
- }
14
- elsif $script {
15
- run_script($script, $targets, '_env_vars' => $env_vars)
16
- }
17
- else {
18
- fail_plan('Must specify either script or command for secure_env_vars')
19
- }
20
- }