bolt 2.30.0 → 2.34.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +12 -12
  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/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +2 -2
  12. data/bolt-modules/out/lib/puppet/functions/out/message.rb +44 -1
  13. data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +3 -0
  14. data/guides/logging.txt +18 -0
  15. data/guides/module.txt +19 -0
  16. data/guides/modulepath.txt +25 -0
  17. data/lib/bolt/bolt_option_parser.rb +6 -1
  18. data/lib/bolt/cli.rb +82 -142
  19. data/lib/bolt/config/modulepath.rb +30 -0
  20. data/lib/bolt/config/options.rb +31 -13
  21. data/lib/bolt/config/transport/options.rb +2 -2
  22. data/lib/bolt/error.rb +13 -3
  23. data/lib/bolt/executor.rb +24 -12
  24. data/lib/bolt/inventory.rb +10 -9
  25. data/lib/bolt/inventory/group.rb +2 -1
  26. data/lib/bolt/module_installer.rb +117 -91
  27. data/lib/bolt/{puppetfile → module_installer}/installer.rb +3 -2
  28. data/lib/bolt/module_installer/puppetfile.rb +117 -0
  29. data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
  30. data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
  31. data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
  32. data/lib/bolt/module_installer/resolver.rb +76 -0
  33. data/lib/bolt/module_installer/specs.rb +93 -0
  34. data/lib/bolt/module_installer/specs/forge_spec.rb +85 -0
  35. data/lib/bolt/module_installer/specs/git_spec.rb +179 -0
  36. data/lib/bolt/outputter.rb +0 -47
  37. data/lib/bolt/outputter/human.rb +46 -16
  38. data/lib/bolt/outputter/json.rb +17 -8
  39. data/lib/bolt/pal.rb +52 -40
  40. data/lib/bolt/pal/yaml_plan.rb +4 -2
  41. data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
  42. data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
  43. data/lib/bolt/plan_creator.rb +160 -0
  44. data/lib/bolt/plugin.rb +2 -2
  45. data/lib/bolt/project.rb +6 -11
  46. data/lib/bolt/project_migrator.rb +1 -1
  47. data/lib/bolt/project_migrator/base.rb +2 -2
  48. data/lib/bolt/project_migrator/config.rb +5 -4
  49. data/lib/bolt/project_migrator/inventory.rb +3 -3
  50. data/lib/bolt/project_migrator/modules.rb +23 -21
  51. data/lib/bolt/puppetdb/config.rb +5 -5
  52. data/lib/bolt/result.rb +23 -11
  53. data/lib/bolt/shell/bash.rb +14 -8
  54. data/lib/bolt/shell/powershell.rb +12 -7
  55. data/lib/bolt/task/run.rb +1 -1
  56. data/lib/bolt/transport/base.rb +18 -18
  57. data/lib/bolt/transport/docker.rb +23 -6
  58. data/lib/bolt/transport/orch.rb +26 -17
  59. data/lib/bolt/transport/remote.rb +3 -3
  60. data/lib/bolt/transport/simple.rb +6 -6
  61. data/lib/bolt/transport/ssh/connection.rb +1 -1
  62. data/lib/bolt/util.rb +5 -0
  63. data/lib/bolt/version.rb +1 -1
  64. data/lib/bolt_server/file_cache.rb +2 -0
  65. data/lib/bolt_server/schemas/partials/task.json +17 -2
  66. data/lib/bolt_server/transport_app.rb +92 -12
  67. data/lib/bolt_spec/bolt_context.rb +4 -2
  68. data/lib/bolt_spec/plans.rb +1 -1
  69. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
  70. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
  71. data/lib/bolt_spec/plans/mock_executor.rb +5 -5
  72. data/lib/bolt_spec/run.rb +1 -1
  73. metadata +24 -9
  74. data/lib/bolt/puppetfile.rb +0 -142
  75. data/lib/bolt/puppetfile/module.rb +0 -90
  76. data/lib/bolt_server/pe/pal.rb +0 -67
  77. data/modules/secure_env_vars/plans/init.pp +0 -20
@@ -11,9 +11,9 @@ module Bolt
11
11
  PROJECT_SETTINGS = {
12
12
  "name" => "The name of the project",
13
13
  "plans" => "An array of plan names to show, if they exist in the project."\
14
- "These plans are included in `bolt plan show` output",
14
+ "These plans are included in `bolt plan show` and `Get-BoltPlan` output",
15
15
  "tasks" => "An array of task names to show, if they exist in the project."\
16
- "These tasks are included in `bolt task show` output"
16
+ "These tasks are included in `bolt task show` and `Get-BoltTask` output"
17
17
  }.freeze
18
18
 
19
19
  attr_reader :path, :data, :config_file, :inventory_file, :hiera_config,
@@ -190,7 +190,7 @@ module Bolt
190
190
  Invalid project name '#{name}' in bolt-project.yaml; project name must begin with a lowercase letter
191
191
  and can include lowercase letters, numbers, and underscores.
192
192
  ERROR_STRING
193
- elsif Dir.children(Bolt::PAL::BOLTLIB_PATH).include?(name)
193
+ elsif Dir.children(Bolt::Config::Modulepath::BOLTLIB_PATH).include?(name)
194
194
  raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
195
195
  "with a built-in Bolt module of the same name."
196
196
  end
@@ -210,14 +210,9 @@ module Bolt
210
210
  raise Bolt::ValidationError, "'modules' in bolt-project.yaml must be an array"
211
211
  end
212
212
 
213
- @data['modules'].each do |mod|
214
- next if (mod.is_a?(Hash) && mod.key?('name')) || mod.is_a?(String)
215
- raise Bolt::ValidationError, "Module declaration #{mod.inspect} must be a hash with a name key"
216
- end
217
-
218
- unknown_keys = modules.flat_map(&:keys).uniq - %w[name version_requirement]
219
- if unknown_keys.any?
220
- @logs << { warn: "Ignoring unknown keys in module declarations: #{unknown_keys.join(', ')}." }
213
+ @data['modules'].each do |spec|
214
+ next if spec.is_a?(Hash) || spec.is_a?(String)
215
+ raise Bolt::ValidationError, "Module specification #{spec.inspect} must be a hash or string"
221
216
  end
222
217
  end
223
218
  end
@@ -21,7 +21,7 @@ module Bolt
21
21
 
22
22
  @outputter.print_message("Migrating project #{@config.project.path}\n\n")
23
23
 
24
- @outputter.print_migrate_step(
24
+ @outputter.print_action_step(
25
25
  "Migrating a Bolt project may make irreversible changes to the project's "\
26
26
  "configuration and inventory files. Before continuing, make sure the "\
27
27
  "project has a backup or uses a version control system."
@@ -12,7 +12,7 @@ module Bolt
12
12
 
13
13
  protected def backup_file(origin_path, backup_dir)
14
14
  unless File.exist?(origin_path)
15
- @outputter.print_migrate_step(
15
+ @outputter.print_action_step(
16
16
  "Could not find file #{origin_path}, skipping backup."
17
17
  )
18
18
  return
@@ -24,7 +24,7 @@ module Bolt
24
24
  filename = File.basename(origin_path)
25
25
  backup_path = File.join(backup_dir, "#{filename}.#{date}.bak")
26
26
 
27
- @outputter.print_migrate_step(
27
+ @outputter.print_action_step(
28
28
  "Backing up #{filename} from #{origin_path} to #{backup_path}"
29
29
  )
30
30
 
@@ -39,7 +39,7 @@ module Bolt
39
39
  backup_file(config_file, backup_dir)
40
40
 
41
41
  begin
42
- @outputter.print_migrate_step(
42
+ @outputter.print_action_step(
43
43
  "Moving transportation configuration options '#{transport_data.keys.join(', ')}' "\
44
44
  "from bolt.yaml to inventory.yaml"
45
45
  )
@@ -51,13 +51,14 @@ module Bolt
51
51
  end
52
52
  end
53
53
 
54
- @outputter.print_migrate_step("Renaming bolt.yaml to bolt-project.yaml")
54
+ @outputter.print_action_step("Renaming bolt.yaml to bolt-project.yaml")
55
55
  FileUtils.mv(config_file, project_file)
56
56
 
57
- @outputter.print_migrate_step(
57
+ command = Bolt::Util.powershell? ? 'Get-Help about_bolt_project' : 'bolt guide project'
58
+ @outputter.print_action_step(
58
59
  "Successfully migrated config. Please add a 'name' key to bolt-project.yaml "\
59
60
  "to use project-level tasks and plans. Learn more about projects by running "\
60
- "'bolt guide project'."
61
+ "'#{command}'."
61
62
  )
62
63
 
63
64
  true
@@ -6,12 +6,12 @@ module Bolt
6
6
  class ProjectMigrator
7
7
  class Inventory < Base
8
8
  def migrate(inventory_file, backup_dir)
9
- inventory_1_to_2(inventory_file, backup_dir)
9
+ inventory1to2(inventory_file, backup_dir)
10
10
  end
11
11
 
12
12
  # Migrates an inventory v1 file to inventory v2.
13
13
  #
14
- private def inventory_1_to_2(inventory_file, backup_dir)
14
+ private def inventory1to2(inventory_file, backup_dir)
15
15
  unless File.exist?(inventory_file)
16
16
  return true
17
17
  end
@@ -28,7 +28,7 @@ module Bolt
28
28
 
29
29
  begin
30
30
  File.write(inventory_file, data.to_yaml)
31
- @outputter.print_migrate_step(
31
+ @outputter.print_action_step(
32
32
  "Successfully migrated Bolt inventory to the latest version."
33
33
  )
34
34
  true
@@ -19,7 +19,7 @@ module Bolt
19
19
 
20
20
  # Notify user to manually migrate modules if using non-default modulepath
21
21
  if configured_modulepath != modulepath
22
- @outputter.print_migrate_step(
22
+ @outputter.print_action_step(
23
23
  "Project has a non-default configured modulepath, unable to automatically "\
24
24
  "migrate project modules. To migrate project modules manually, see "\
25
25
  "http://pup.pt/bolt-modules"
@@ -42,30 +42,32 @@ module Bolt
42
42
  # to the new moduledir.
43
43
  #
44
44
  private def migrate_modules_from_puppetfile(config, puppetfile_path, managed_moduledir, modulepath)
45
- require 'bolt/puppetfile'
46
- require 'bolt/puppetfile/installer'
45
+ require 'bolt/module_installer/installer'
46
+ require 'bolt/module_installer/puppetfile'
47
+ require 'bolt/module_installer/resolver'
48
+ require 'bolt/module_installer/specs'
47
49
 
48
50
  begin
49
- @outputter.print_migrate_step("Parsing Puppetfile at #{puppetfile_path}")
50
- puppetfile = Bolt::Puppetfile.parse(puppetfile_path, skip_unsupported_modules: true)
51
+ @outputter.print_action_step("Parsing Puppetfile at #{puppetfile_path}")
52
+ puppetfile = Bolt::ModuleInstaller::Puppetfile.parse(puppetfile_path, skip_unsupported_modules: true)
51
53
  rescue Bolt::Error => e
52
- @outputter.print_migrate_error("#{e.message}\nSkipping module migration.")
54
+ @outputter.print_action_error("#{e.message}\nSkipping module migration.")
53
55
  return false
54
56
  end
55
57
 
56
58
  # Prompt for direct dependencies
57
59
  modules = select_modules(puppetfile.modules)
58
60
 
59
- # Create new Puppetfile object
60
- puppetfile = Bolt::Puppetfile.new(modules)
61
+ # Create specs to resolve from
62
+ specs = Bolt::ModuleInstaller::Specs.new(modules.map(&:to_hash))
61
63
 
62
64
  # Attempt to resolve dependencies
63
65
  begin
64
66
  @outputter.print_message('')
65
- @outputter.print_migrate_step("Resolving module dependencies, this may take a moment")
66
- puppetfile.resolve
67
+ @outputter.print_action_step("Resolving module dependencies, this may take a moment")
68
+ puppetfile = Bolt::ModuleInstaller::Resolver.new.resolve(specs)
67
69
  rescue Bolt::Error => e
68
- @outputter.print_migrate_error("#{e.message}\nSkipping module migration.")
70
+ @outputter.print_action_error("#{e.message}\nSkipping module migration.")
69
71
  return false
70
72
  end
71
73
 
@@ -90,17 +92,17 @@ module Bolt
90
92
  # Show the new Puppetfile content
91
93
  message = "Generated new Puppetfile content:\n\n"
92
94
  message += puppetfile.modules.map(&:to_spec).join("\n").to_s
93
- @outputter.print_migrate_step(message)
95
+ @outputter.print_action_step(message)
94
96
 
95
97
  # Write Puppetfile
96
- @outputter.print_migrate_step("Updating Puppetfile at #{puppetfile_path}")
98
+ @outputter.print_action_step("Updating Puppetfile at #{puppetfile_path}")
97
99
  puppetfile.write(puppetfile_path, managed_moduledir)
98
100
 
99
101
  # Install Puppetfile
100
- @outputter.print_migrate_step("Syncing modules from #{puppetfile_path} to #{managed_moduledir}")
101
- Bolt::Puppetfile::Installer.new({}).install(puppetfile_path, managed_moduledir)
102
+ @outputter.print_action_step("Syncing modules from #{puppetfile_path} to #{managed_moduledir}")
103
+ Bolt::ModuleInstaller::Installer.new.install(puppetfile_path, managed_moduledir)
102
104
  else
103
- @outputter.print_migrate_step(
105
+ @outputter.print_action_step(
104
106
  "Project does not include any managed modules, deleting Puppetfile "\
105
107
  "at #{puppetfile_path}"
106
108
  )
@@ -112,7 +114,7 @@ module Bolt
112
114
  # the selected modules.
113
115
  #
114
116
  private def select_modules(modules)
115
- @outputter.print_migrate_step(
117
+ @outputter.print_action_step(
116
118
  "Select modules that are direct dependencies of your project. Bolt will "\
117
119
  "automatically manage dependencies for each module selected, so do not "\
118
120
  "select a module's dependencies unless you use content from it directly "\
@@ -123,7 +125,7 @@ module Bolt
123
125
  return modules if all
124
126
 
125
127
  modules.select do |mod|
126
- Bolt::Util.prompt_yes_no("Select #{mod.title}?", @outputter)
128
+ Bolt::Util.prompt_yes_no("Select #{mod.full_name}?", @outputter)
127
129
  end
128
130
  end
129
131
 
@@ -135,7 +137,7 @@ module Bolt
135
137
  sources.select! { |source| Dir.exist?(source) }
136
138
 
137
139
  if sources.any?
138
- @outputter.print_migrate_step(
140
+ @outputter.print_action_step(
139
141
  "Moving modules from #{sources.join(', ')} to #{moduledir}"
140
142
  )
141
143
 
@@ -166,7 +168,7 @@ module Bolt
166
168
  # Deletes modules from a specified directory.
167
169
  #
168
170
  private def delete_modules(moduledir, modules)
169
- @outputter.print_migrate_step("Cleaning up #{moduledir}")
171
+ @outputter.print_action_step("Cleaning up #{moduledir}")
170
172
  moduledir = Pathname.new(moduledir)
171
173
 
172
174
  modules.each do |mod|
@@ -178,7 +180,7 @@ module Bolt
178
180
  # Adds a list of modules to the project configuration file.
179
181
  #
180
182
  private def update_project_config(modules, config_file)
181
- @outputter.print_migrate_step("Updating project configuration at #{config_file}")
183
+ @outputter.print_action_step("Updating project configuration at #{config_file}")
182
184
  data = Bolt::Util.read_optional_yaml_hash(config_file, 'project')
183
185
  data.merge!('modules' => modules)
184
186
  data.delete('modulepath')
@@ -6,14 +6,14 @@ require 'bolt/util'
6
6
  module Bolt
7
7
  module PuppetDB
8
8
  class Config
9
- if !ENV['HOME'].nil?
10
- DEFAULT_TOKEN = File.expand_path('~/.puppetlabs/token')
11
- DEFAULT_CONFIG = { user: File.expand_path('~/.puppetlabs/client-tools/puppetdb.conf'),
12
- global: '/etc/puppetlabs/client-tools/puppetdb.conf' }.freeze
13
- else
9
+ if ENV['HOME'].nil?
14
10
  DEFAULT_TOKEN = Bolt::Util.windows? ? 'nul' : '/dev/null'
15
11
  DEFAULT_CONFIG = { user: '/etc/puppetlabs/puppet/puppetdb.conf',
16
12
  global: '/etc/puppetlabs/puppet/puppetdb.conf' }.freeze
13
+ else
14
+ DEFAULT_TOKEN = File.expand_path('~/.puppetlabs/token')
15
+ DEFAULT_CONFIG = { user: File.expand_path('~/.puppetlabs/client-tools/puppetdb.conf'),
16
+ global: '/etc/puppetlabs/client-tools/puppetdb.conf' }.freeze
17
17
 
18
18
  end
19
19
 
@@ -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
 
@@ -202,13 +207,14 @@ module Bolt
202
207
  end
203
208
 
204
209
  def handle_sudo_errors(err)
205
- if err =~ /^#{conn.user} is not in the sudoers file\./
210
+ case err
211
+ when /^#{conn.user} is not in the sudoers file\./
206
212
  @logger.trace { err }
207
213
  raise Bolt::Node::EscalateError.new(
208
214
  "User #{conn.user} does not have sudo permission on #{target}",
209
215
  'SUDO_DENIED'
210
216
  )
211
- elsif err =~ /^Sorry, try again\./
217
+ when /^Sorry, try again\./
212
218
  @logger.trace { err }
213
219
  raise Bolt::Node::EscalateError.new(
214
220
  "Sudo password for user #{conn.user} not recognized on #{target}",
@@ -11,7 +11,7 @@ module Bolt
11
11
  def initialize(target, conn)
12
12
  super
13
13
 
14
- extensions = [target.options['extensions'] || []].flatten.map { |ext| ext[0] != '.' ? '.' + ext : ext }
14
+ extensions = [target.options['extensions'] || []].flatten.map { |ext| ext[0] == '.' ? ext : '.' + ext }
15
15
  extensions += target.options['interpreters'].keys if target.options['interpreters']
16
16
  @extensions = DEFAULT_EXTENSIONS + extensions
17
17
  end
@@ -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