bolt 2.16.0 → 2.17.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +6 -4
- data/lib/bolt/bolt_option_parser.rb +14 -7
- data/lib/bolt/cli.rb +10 -1
- data/lib/bolt/config.rb +3 -21
- data/lib/bolt/config/options.rb +325 -173
- data/lib/bolt/config/transport/options.rb +309 -160
- data/lib/bolt/logger.rb +3 -1
- data/lib/bolt/outputter.rb +1 -1
- data/lib/bolt/outputter/rainbow.rb +5 -1
- data/lib/bolt/pal.rb +20 -8
- data/lib/bolt/shell/bash.rb +21 -33
- data/lib/bolt/shell/powershell.rb +11 -7
- data/lib/bolt/transport/docker.rb +8 -4
- data/lib/bolt/transport/orch.rb +8 -0
- data/lib/bolt/version.rb +1 -1
- metadata +15 -29
data/lib/bolt/logger.rb
CHANGED
@@ -89,8 +89,10 @@ module Bolt
|
|
89
89
|
:notice
|
90
90
|
end
|
91
91
|
|
92
|
+
# Explicitly check the log level names instead of the log level number, as levels
|
93
|
+
# that are stringified integers (e.g. "level" => "42") will return a truthy value
|
92
94
|
def self.valid_level?(level)
|
93
|
-
|
95
|
+
Logging::LEVELS.include?(Logging.levelify(level))
|
94
96
|
end
|
95
97
|
|
96
98
|
def self.levels
|
data/lib/bolt/outputter.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bolt/pal'
|
4
|
-
require 'paint'
|
5
4
|
|
6
5
|
module Bolt
|
7
6
|
class Outputter
|
8
7
|
class Rainbow < Bolt::Outputter::Human
|
9
8
|
def initialize(color, verbose, trace, stream = $stdout)
|
9
|
+
begin
|
10
|
+
require 'paint'
|
11
|
+
rescue LoadError
|
12
|
+
raise "The 'paint' gem is required to use the rainbow outputter."
|
13
|
+
end
|
10
14
|
super
|
11
15
|
@line_color = 0
|
12
16
|
@color = 0
|
data/lib/bolt/pal.rb
CHANGED
@@ -15,25 +15,36 @@ module Bolt
|
|
15
15
|
# PALError is used to convert errors from executing puppet code into
|
16
16
|
# Bolt::Errors
|
17
17
|
class PALError < Bolt::Error
|
18
|
-
# Puppet sometimes rescues exceptions notes the location and reraises.
|
19
|
-
# Return the original error.
|
20
18
|
def self.from_preformatted_error(err)
|
21
19
|
if err.cause&.is_a? Bolt::Error
|
22
20
|
err.cause
|
23
21
|
else
|
24
|
-
from_error(err
|
22
|
+
from_error(err)
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
28
26
|
# Generate a Bolt::Pal::PALError for non-bolt errors
|
29
27
|
def self.from_error(err)
|
30
|
-
|
28
|
+
# Use the original error message if available
|
29
|
+
message = err.cause ? err.cause.message : err.message
|
30
|
+
|
31
|
+
# Provide the location of an error if it came from a plan
|
32
|
+
details = if defined?(err.file) && err.file
|
33
|
+
{ file: err.file,
|
34
|
+
line: err.line,
|
35
|
+
column: err.pos }.compact
|
36
|
+
else
|
37
|
+
{}
|
38
|
+
end
|
39
|
+
|
40
|
+
e = new(message, details)
|
41
|
+
|
31
42
|
e.set_backtrace(err.backtrace)
|
32
43
|
e
|
33
44
|
end
|
34
45
|
|
35
|
-
def initialize(msg)
|
36
|
-
super(msg, 'bolt/pal-error')
|
46
|
+
def initialize(msg, details = {})
|
47
|
+
super(msg, 'bolt/pal-error', details)
|
37
48
|
end
|
38
49
|
end
|
39
50
|
|
@@ -159,8 +170,9 @@ module Bolt
|
|
159
170
|
if e.issue_code == :UNKNOWN_VARIABLE &&
|
160
171
|
%w[facts trusted server_facts settings].include?(e.arguments[:name])
|
161
172
|
message = "Evaluation Error: Variable '#{e.arguments[:name]}' is not available in the current scope "\
|
162
|
-
|
163
|
-
|
173
|
+
"unless explicitly defined."
|
174
|
+
details = { file: e.file, line: e.line, column: e.pos }
|
175
|
+
PALError.new(message, details)
|
164
176
|
else
|
165
177
|
PALError.from_preformatted_error(e)
|
166
178
|
end
|
data/lib/bolt/shell/bash.rb
CHANGED
@@ -23,7 +23,7 @@ module Bolt
|
|
23
23
|
|
24
24
|
def run_command(command, options = {})
|
25
25
|
running_as(options[:run_as]) do
|
26
|
-
output = execute(command, sudoable: true)
|
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,
|
@@ -58,7 +58,7 @@ module Bolt
|
|
58
58
|
with_tmpdir do |dir|
|
59
59
|
path = write_executable(dir.to_s, script)
|
60
60
|
dir.chown(run_as)
|
61
|
-
output = execute([path, *arguments], sudoable: true)
|
61
|
+
output = execute([path, *arguments], environment: options[:env_vars], sudoable: true)
|
62
62
|
Bolt::Result.for_command(target,
|
63
63
|
output.stdout.string,
|
64
64
|
output.stderr.string,
|
@@ -170,7 +170,7 @@ module Bolt
|
|
170
170
|
def check_sudo(out, inp, stdin)
|
171
171
|
buffer = out.readpartial(CHUNK_SIZE)
|
172
172
|
# Split on newlines, including the newline
|
173
|
-
lines = buffer.split(/(
|
173
|
+
lines = buffer.split(/(?<=\n)/)
|
174
174
|
# handle_sudo will return the line if it is not a sudo prompt or error
|
175
175
|
lines.map! { |line| handle_sudo(inp, line, stdin) }
|
176
176
|
lines.join("")
|
@@ -277,31 +277,8 @@ module Bolt
|
|
277
277
|
end
|
278
278
|
end
|
279
279
|
|
280
|
-
|
281
|
-
|
282
|
-
# for task input data because the sudo password has already either been
|
283
|
-
# provided on stdin or was not needed.
|
284
|
-
def prepend_sudo_success(sudo_id, command_str)
|
285
|
-
command_str = "cd; #{command_str}" if conn.reset_cwd?
|
286
|
-
"sh -c #{Shellwords.shellescape("echo #{sudo_id} 1>&2; #{command_str}")}"
|
287
|
-
end
|
288
|
-
|
289
|
-
def prepend_chdir(command_str)
|
290
|
-
"sh -c #{Shellwords.shellescape("cd; #{command_str}")}"
|
291
|
-
end
|
292
|
-
|
293
|
-
# A helper to build up a single string that contains all of the options for
|
294
|
-
# privilege escalation. A wrapper script is used to direct task input to stdin
|
295
|
-
# when a tty is allocated and thus we do not need to prepend_sudo_success when
|
296
|
-
# using the wrapper or when the task does not require stdin data.
|
297
|
-
def build_sudoable_command_str(command_str, sudo_str, sudo_id, options)
|
298
|
-
if options[:stdin] && !options[:wrapper]
|
299
|
-
"#{sudo_str} #{prepend_sudo_success(sudo_id, command_str)}"
|
300
|
-
elsif conn.reset_cwd?
|
301
|
-
"#{sudo_str} #{prepend_chdir(command_str)}"
|
302
|
-
else
|
303
|
-
"#{sudo_str} #{command_str}"
|
304
|
-
end
|
280
|
+
def sudo_success(sudo_id)
|
281
|
+
"echo #{sudo_id} 1>&2"
|
305
282
|
end
|
306
283
|
|
307
284
|
# Returns string with the interpreter conditionally prepended
|
@@ -322,13 +299,15 @@ module Bolt
|
|
322
299
|
escalate = sudoable && run_as && conn.user != run_as
|
323
300
|
use_sudo = escalate && @target.options['run-as-command'].nil?
|
324
301
|
|
325
|
-
|
302
|
+
# Depending on the transport, whether we're using sudo and whether
|
303
|
+
# there are environment variables to set, we may need to stitch
|
304
|
+
# together multiple commands into a single sh invocation
|
305
|
+
commands = [inject_interpreter(options[:interpreter], command)]
|
326
306
|
|
327
307
|
if options[:environment]
|
328
|
-
|
308
|
+
env_decl = options[:environment].map do |env, val|
|
329
309
|
"#{env}=#{Shellwords.shellescape(val)}"
|
330
|
-
end
|
331
|
-
command_str = "#{env_decls.join(' ')} #{command_str}"
|
310
|
+
end.join(' ')
|
332
311
|
end
|
333
312
|
|
334
313
|
if escalate
|
@@ -340,9 +319,18 @@ module Bolt
|
|
340
319
|
else
|
341
320
|
Shellwords.shelljoin(@target.options['run-as-command'] + [run_as])
|
342
321
|
end
|
343
|
-
|
322
|
+
commands.unshift('cd') if conn.reset_cwd?
|
323
|
+
commands.unshift(sudo_success(@sudo_id)) if options[:stdin] && !options[:wrapper]
|
344
324
|
end
|
345
325
|
|
326
|
+
command_str = if sudo_str || env_decl
|
327
|
+
"sh -c #{Shellwords.shellescape(commands.join('; '))}"
|
328
|
+
else
|
329
|
+
commands.last
|
330
|
+
end
|
331
|
+
|
332
|
+
command_str = [sudo_str, env_decl, command_str].compact.join(' ')
|
333
|
+
|
346
334
|
@logger.debug { "Executing: #{command_str}" }
|
347
335
|
|
348
336
|
in_buffer = if !use_sudo && options[:stdin]
|
@@ -71,8 +71,10 @@ module Bolt
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
def
|
75
|
-
|
74
|
+
def env_declarations(env_vars)
|
75
|
+
env_vars.map do |var, val|
|
76
|
+
"[Environment]::SetEnvironmentVariable('#{var}', @'\n#{val}\n'@)"
|
77
|
+
end
|
76
78
|
end
|
77
79
|
|
78
80
|
def quote_string(string)
|
@@ -166,7 +168,9 @@ module Bolt
|
|
166
168
|
Bolt::Result.for_upload(target, source, destination)
|
167
169
|
end
|
168
170
|
|
169
|
-
def run_command(command,
|
171
|
+
def run_command(command, options = {})
|
172
|
+
command = [*env_declarations(options[:env_vars]), command].join("\r\n") if options[:env_vars]
|
173
|
+
|
170
174
|
output = execute(command)
|
171
175
|
Bolt::Result.for_command(target,
|
172
176
|
output.stdout.string,
|
@@ -175,7 +179,7 @@ module Bolt
|
|
175
179
|
'command', command)
|
176
180
|
end
|
177
181
|
|
178
|
-
def run_script(script, arguments,
|
182
|
+
def run_script(script, arguments, options = {})
|
179
183
|
# unpack any Sensitive data
|
180
184
|
arguments = unwrap_sensitive_args(arguments)
|
181
185
|
with_tmpdir do |dir|
|
@@ -187,6 +191,8 @@ module Bolt
|
|
187
191
|
args += escape_arguments(arguments)
|
188
192
|
execute_process(path, args)
|
189
193
|
end
|
194
|
+
command = [*env_declarations(options[:env_vars]), command].join("\r\n") if options[:env_vars]
|
195
|
+
|
190
196
|
output = execute(command)
|
191
197
|
Bolt::Result.for_command(target,
|
192
198
|
output.stdout.string,
|
@@ -237,9 +243,7 @@ module Bolt
|
|
237
243
|
end
|
238
244
|
|
239
245
|
env_assignments = if Bolt::Task::ENVIRONMENT_METHODS.include?(input_method)
|
240
|
-
envify_params(arguments)
|
241
|
-
set_env(arg, val)
|
242
|
-
end
|
246
|
+
env_declarations(envify_params(arguments))
|
243
247
|
else
|
244
248
|
[]
|
245
249
|
end
|
@@ -39,7 +39,9 @@ module Bolt
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def run_command(target, command, options = {})
|
42
|
-
|
42
|
+
execute_options = {}
|
43
|
+
execute_options[:tty] = target.options['tty']
|
44
|
+
execute_options[:environment] = options[:env_vars]
|
43
45
|
|
44
46
|
if target.options['shell-command'] && !target.options['shell-command'].empty?
|
45
47
|
# escape any double quotes in command
|
@@ -47,19 +49,21 @@ module Bolt
|
|
47
49
|
command = "#{target.options['shell-command']} \" #{command}\""
|
48
50
|
end
|
49
51
|
with_connection(target) do |conn|
|
50
|
-
stdout, stderr, exitcode = conn.execute(*Shellwords.split(command),
|
52
|
+
stdout, stderr, exitcode = conn.execute(*Shellwords.split(command), execute_options)
|
51
53
|
Bolt::Result.for_command(target, stdout, stderr, exitcode, 'command', command)
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
def run_script(target, script, arguments,
|
57
|
+
def run_script(target, script, arguments, options = {})
|
56
58
|
# unpack any Sensitive data
|
57
59
|
arguments = unwrap_sensitive_args(arguments)
|
60
|
+
execute_options = {}
|
61
|
+
execute_options[:environment] = options[:env_vars]
|
58
62
|
|
59
63
|
with_connection(target) do |conn|
|
60
64
|
conn.with_remote_tmpdir do |dir|
|
61
65
|
remote_path = conn.write_remote_executable(dir, script)
|
62
|
-
stdout, stderr, exitcode = conn.execute(remote_path, *arguments,
|
66
|
+
stdout, stderr, exitcode = conn.execute(remote_path, *arguments, execute_options)
|
63
67
|
Bolt::Result.for_command(target, stdout, stderr, exitcode, 'script', script)
|
64
68
|
end
|
65
69
|
end
|
data/lib/bolt/transport/orch.rb
CHANGED
@@ -82,6 +82,10 @@ module Bolt
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def batch_command(targets, command, options = {}, &callback)
|
85
|
+
if options[:env_vars] && !options[:env_vars].empty?
|
86
|
+
raise NotImplementedError, "pcp transport does not support setting environment variables"
|
87
|
+
end
|
88
|
+
|
85
89
|
params = {
|
86
90
|
'command' => command
|
87
91
|
}
|
@@ -98,6 +102,10 @@ module Bolt
|
|
98
102
|
end
|
99
103
|
|
100
104
|
def batch_script(targets, script, arguments, options = {}, &callback)
|
105
|
+
if options[:env_vars] && !options[:env_vars].empty?
|
106
|
+
raise NotImplementedError, "pcp transport does not support setting environment variables"
|
107
|
+
end
|
108
|
+
|
101
109
|
content = File.open(script, &:read)
|
102
110
|
content = Base64.encode64(content)
|
103
111
|
params = {
|
data/lib/bolt/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -178,20 +178,6 @@ dependencies:
|
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0.4'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: paint
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '2.2'
|
188
|
-
type: :runtime
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '2.2'
|
195
181
|
- !ruby/object:Gem::Dependency
|
196
182
|
name: puppet
|
197
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -213,47 +199,47 @@ dependencies:
|
|
213
199
|
- !ruby/object:Gem::Version
|
214
200
|
version: '7'
|
215
201
|
- !ruby/object:Gem::Dependency
|
216
|
-
name:
|
202
|
+
name: puppetfile-resolver
|
217
203
|
requirement: !ruby/object:Gem::Requirement
|
218
204
|
requirements:
|
219
|
-
- - "
|
205
|
+
- - "~>"
|
220
206
|
- !ruby/object:Gem::Version
|
221
|
-
version: 1.
|
207
|
+
version: 0.1.0
|
222
208
|
type: :runtime
|
223
209
|
prerelease: false
|
224
210
|
version_requirements: !ruby/object:Gem::Requirement
|
225
211
|
requirements:
|
226
|
-
- - "
|
212
|
+
- - "~>"
|
227
213
|
- !ruby/object:Gem::Version
|
228
|
-
version: 1.
|
214
|
+
version: 0.1.0
|
229
215
|
- !ruby/object:Gem::Dependency
|
230
|
-
name: puppet-
|
216
|
+
name: puppet-resource_api
|
231
217
|
requirement: !ruby/object:Gem::Requirement
|
232
218
|
requirements:
|
233
|
-
- - "
|
219
|
+
- - ">="
|
234
220
|
- !ruby/object:Gem::Version
|
235
|
-
version:
|
221
|
+
version: 1.8.1
|
236
222
|
type: :runtime
|
237
223
|
prerelease: false
|
238
224
|
version_requirements: !ruby/object:Gem::Requirement
|
239
225
|
requirements:
|
240
|
-
- - "
|
226
|
+
- - ">="
|
241
227
|
- !ruby/object:Gem::Version
|
242
|
-
version:
|
228
|
+
version: 1.8.1
|
243
229
|
- !ruby/object:Gem::Dependency
|
244
|
-
name:
|
230
|
+
name: puppet-strings
|
245
231
|
requirement: !ruby/object:Gem::Requirement
|
246
232
|
requirements:
|
247
233
|
- - "~>"
|
248
234
|
- !ruby/object:Gem::Version
|
249
|
-
version:
|
235
|
+
version: '2.3'
|
250
236
|
type: :runtime
|
251
237
|
prerelease: false
|
252
238
|
version_requirements: !ruby/object:Gem::Requirement
|
253
239
|
requirements:
|
254
240
|
- - "~>"
|
255
241
|
- !ruby/object:Gem::Version
|
256
|
-
version:
|
242
|
+
version: '2.3'
|
257
243
|
- !ruby/object:Gem::Dependency
|
258
244
|
name: r10k
|
259
245
|
requirement: !ruby/object:Gem::Requirement
|