bolt 2.6.0 → 2.11.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/Puppetfile +4 -3
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +27 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +192 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +122 -0
- data/bolt-modules/boltlib/types/planresult.pp +12 -1
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +2 -1
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +3 -1
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +43 -0
- data/lib/bolt/analytics.rb +1 -1
- data/lib/bolt/applicator.rb +3 -2
- data/lib/bolt/apply_inventory.rb +1 -1
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/apply_target.rb +11 -2
- data/lib/bolt/bolt_option_parser.rb +27 -7
- data/lib/bolt/catalog.rb +32 -3
- data/lib/bolt/cli.rb +52 -22
- data/lib/bolt/config.rb +51 -27
- data/lib/bolt/config/transport/base.rb +3 -3
- data/lib/bolt/config/transport/docker.rb +7 -1
- data/lib/bolt/config/transport/local.rb +9 -1
- data/lib/bolt/config/transport/orch.rb +4 -2
- data/lib/bolt/config/transport/remote.rb +2 -0
- data/lib/bolt/config/transport/ssh.rb +81 -3
- data/lib/bolt/config/transport/winrm.rb +6 -1
- data/lib/bolt/executor.rb +38 -0
- data/lib/bolt/inventory.rb +2 -1
- data/lib/bolt/inventory/group.rb +1 -0
- data/lib/bolt/inventory/inventory.rb +9 -0
- data/lib/bolt/inventory/target.rb +17 -1
- data/lib/bolt/node/output.rb +1 -1
- data/lib/bolt/outputter/human.rb +5 -4
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/pal.rb +32 -14
- data/lib/bolt/pal/yaml_plan.rb +1 -0
- data/lib/bolt/plugin.rb +14 -8
- data/lib/bolt/plugin/env_var.rb +2 -1
- data/lib/bolt/plugin/module.rb +40 -7
- data/lib/bolt/plugin/prompt.rb +1 -1
- data/lib/bolt/plugin/puppetdb.rb +5 -2
- data/lib/bolt/project.rb +135 -0
- data/lib/bolt/puppetdb/config.rb +16 -28
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/resource_instance.rb +126 -0
- data/lib/bolt/result.rb +46 -23
- data/lib/bolt/result_set.rb +2 -5
- data/lib/bolt/secret.rb +20 -4
- data/lib/bolt/shell/bash.rb +27 -14
- data/lib/bolt/shell/bash/tmpdir.rb +1 -1
- data/lib/bolt/shell/powershell.rb +43 -15
- data/lib/bolt/shell/powershell/snippets.rb +1 -1
- data/lib/bolt/target.rb +18 -2
- data/lib/bolt/transport/base.rb +24 -8
- data/lib/bolt/transport/docker.rb +3 -3
- data/lib/bolt/transport/docker/connection.rb +11 -7
- data/lib/bolt/transport/local/connection.rb +13 -7
- data/lib/bolt/transport/orch.rb +5 -1
- data/lib/bolt/transport/ssh.rb +6 -2
- data/lib/bolt/transport/ssh/connection.rb +26 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +110 -0
- data/lib/bolt/transport/winrm/connection.rb +10 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -38
- data/lib/bolt_server/transport_app.rb +7 -7
- data/lib/bolt_spec/bolt_context.rb +3 -6
- data/lib/bolt_spec/plans.rb +78 -8
- data/lib/bolt_spec/plans/action_stubs.rb +37 -7
- data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +55 -0
- data/lib/bolt_spec/plans/mock_executor.rb +62 -2
- data/lib/bolt_spec/run.rb +10 -13
- metadata +26 -7
- data/lib/bolt/boltdir.rb +0 -54
- data/lib/bolt/plugin/pkcs7.rb +0 -104
- data/lib/bolt/secret/base.rb +0 -41
data/lib/bolt/result_set.rb
CHANGED
@@ -99,17 +99,14 @@ module Bolt
|
|
99
99
|
self.class == other.class && @results == other.results
|
100
100
|
end
|
101
101
|
|
102
|
-
def to_a
|
103
|
-
@results.map(&:status_hash)
|
104
|
-
end
|
105
|
-
|
106
102
|
def to_json(opts = nil)
|
107
|
-
|
103
|
+
to_data.to_json(opts)
|
108
104
|
end
|
109
105
|
|
110
106
|
def to_data
|
111
107
|
@results.map(&:to_data)
|
112
108
|
end
|
109
|
+
alias to_a to_data
|
113
110
|
|
114
111
|
def to_s
|
115
112
|
to_json
|
data/lib/bolt/secret.rb
CHANGED
@@ -1,17 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/plugin'
|
4
|
+
|
3
5
|
module Bolt
|
4
6
|
class Secret
|
7
|
+
KNOWN_KEYS = {
|
8
|
+
'createkeys' => %w[keysize private_key public_key],
|
9
|
+
'encrypt' => %w[public_key],
|
10
|
+
'decrypt' => %w[private_key public_key]
|
11
|
+
}.freeze
|
12
|
+
|
5
13
|
def self.execute(plugins, outputter, options)
|
6
|
-
|
14
|
+
name = options[:plugin] || 'pkcs7'
|
15
|
+
plugin = plugins.by_name(name)
|
16
|
+
|
17
|
+
unless plugin
|
18
|
+
raise Bolt::Plugin::PluginError::Unknown, name
|
19
|
+
end
|
20
|
+
|
7
21
|
case options[:action]
|
8
22
|
when 'createkeys'
|
9
|
-
|
23
|
+
opts = { 'force' => options[:force] }.compact
|
24
|
+
result = plugins.get_hook(name, :secret_createkeys).call(opts)
|
25
|
+
outputter.print_message(result)
|
10
26
|
when 'encrypt'
|
11
|
-
encrypted = plugins.get_hook(
|
27
|
+
encrypted = plugins.get_hook(name, :secret_encrypt).call('plaintext_value' => options[:object])
|
12
28
|
outputter.print_message(encrypted)
|
13
29
|
when 'decrypt'
|
14
|
-
decrypted = plugins.get_hook(
|
30
|
+
decrypted = plugins.get_hook(name, :secret_decrypt).call('encrypted_value' => options[:object])
|
15
31
|
outputter.print_message(decrypted)
|
16
32
|
end
|
17
33
|
|
data/lib/bolt/shell/bash.rb
CHANGED
@@ -34,7 +34,7 @@ module Bolt
|
|
34
34
|
|
35
35
|
def upload(source, destination, options = {})
|
36
36
|
running_as(options[:run_as]) do
|
37
|
-
|
37
|
+
with_tmpdir do |dir|
|
38
38
|
basename = File.basename(destination)
|
39
39
|
tmpfile = File.join(dir.to_s, basename)
|
40
40
|
conn.copy_file(source, tmpfile)
|
@@ -55,7 +55,7 @@ module Bolt
|
|
55
55
|
arguments = unwrap_sensitive_args(arguments)
|
56
56
|
|
57
57
|
running_as(options[:run_as]) do
|
58
|
-
|
58
|
+
with_tmpdir do |dir|
|
59
59
|
path = write_executable(dir.to_s, script)
|
60
60
|
dir.chown(run_as)
|
61
61
|
output = execute([path, *arguments], sudoable: true)
|
@@ -86,7 +86,7 @@ module Bolt
|
|
86
86
|
# unpack any Sensitive data
|
87
87
|
arguments = unwrap_sensitive_args(arguments)
|
88
88
|
|
89
|
-
|
89
|
+
with_tmpdir do |dir|
|
90
90
|
if extra_files.empty?
|
91
91
|
task_dir = dir
|
92
92
|
else
|
@@ -150,8 +150,14 @@ module Bolt
|
|
150
150
|
end
|
151
151
|
elsif err =~ /^#{@sudo_id}/
|
152
152
|
if sudo_stdin
|
153
|
-
|
154
|
-
|
153
|
+
begin
|
154
|
+
stdin.write("#{sudo_stdin}\n")
|
155
|
+
stdin.close
|
156
|
+
# If a task has stdin as an input_method but doesn't actually read
|
157
|
+
# from stdin, the task may return and close the input stream before
|
158
|
+
# we finish writing
|
159
|
+
rescue Errno::EPIPE
|
160
|
+
end
|
155
161
|
end
|
156
162
|
''
|
157
163
|
else
|
@@ -234,7 +240,7 @@ module Bolt
|
|
234
240
|
end
|
235
241
|
end
|
236
242
|
|
237
|
-
def
|
243
|
+
def make_tmpdir
|
238
244
|
tmpdir = @target.options.fetch('tmpdir', '/tmp')
|
239
245
|
script_dir = @target.options.fetch('script-dir', SecureRandom.uuid)
|
240
246
|
tmppath = File.join(tmpdir, script_dir)
|
@@ -242,7 +248,7 @@ module Bolt
|
|
242
248
|
|
243
249
|
result = execute(command)
|
244
250
|
if result.exit_code != 0
|
245
|
-
raise Bolt::Node::FileError.new("Could not make
|
251
|
+
raise Bolt::Node::FileError.new("Could not make tmpdir: #{result.stderr.string}", 'TMPDIR_ERROR')
|
246
252
|
end
|
247
253
|
path = tmppath || result.stdout.string.chomp
|
248
254
|
Bolt::Shell::Bash::Tmpdir.new(self, path)
|
@@ -256,13 +262,19 @@ module Bolt
|
|
256
262
|
remote_path
|
257
263
|
end
|
258
264
|
|
259
|
-
# A helper to create and delete a
|
265
|
+
# A helper to create and delete a tmpdir on the remote system. Yields the
|
260
266
|
# directory name.
|
261
|
-
def
|
262
|
-
dir =
|
267
|
+
def with_tmpdir
|
268
|
+
dir = make_tmpdir
|
263
269
|
yield dir
|
264
270
|
ensure
|
265
|
-
dir
|
271
|
+
if dir
|
272
|
+
if target.options['cleanup']
|
273
|
+
dir.delete
|
274
|
+
else
|
275
|
+
@logger.warn("Skipping cleanup of tmpdir #{dir}")
|
276
|
+
end
|
277
|
+
end
|
266
278
|
end
|
267
279
|
|
268
280
|
# In the case where a task is run with elevated privilege and needs stdin
|
@@ -341,9 +353,9 @@ module Bolt
|
|
341
353
|
# Chunks of this size will be read in one iteration
|
342
354
|
index = 0
|
343
355
|
timeout = 0.1
|
356
|
+
result_output = Bolt::Node::Output.new
|
344
357
|
|
345
358
|
inp, out, err, t = conn.execute(command_str)
|
346
|
-
result_output = Bolt::Node::Output.new
|
347
359
|
read_streams = { out => String.new,
|
348
360
|
err => String.new }
|
349
361
|
write_stream = in_buffer.empty? ? [] : [inp]
|
@@ -393,8 +405,9 @@ module Bolt
|
|
393
405
|
write_stream = []
|
394
406
|
end
|
395
407
|
end
|
396
|
-
# If a task has stdin as an input_method but doesn't actually
|
397
|
-
#
|
408
|
+
# If a task has stdin as an input_method but doesn't actually read
|
409
|
+
# from stdin, the task may return and close the input stream before
|
410
|
+
# we finish writing
|
398
411
|
rescue Errno::EPIPE
|
399
412
|
write_stream = []
|
400
413
|
end
|
@@ -48,7 +48,7 @@ module Bolt
|
|
48
48
|
def delete
|
49
49
|
result = @shell.execute(['rm', '-rf', @path], sudoable: true, run_as: @owner)
|
50
50
|
if result.exit_code != 0
|
51
|
-
@logger.warn("Failed to clean up
|
51
|
+
@logger.warn("Failed to clean up tmpdir '#{@path}': #{result.stderr.string}")
|
52
52
|
end
|
53
53
|
# For testing
|
54
54
|
result.stderr.string
|
@@ -6,7 +6,7 @@ module Bolt
|
|
6
6
|
class Shell
|
7
7
|
class Powershell < Shell
|
8
8
|
DEFAULT_EXTENSIONS = Set.new(%w[.ps1 .rb .pp])
|
9
|
-
PS_ARGS = %w[-NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass
|
9
|
+
PS_ARGS = %w[-NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass].freeze
|
10
10
|
|
11
11
|
def initialize(target, conn)
|
12
12
|
super
|
@@ -45,7 +45,7 @@ module Bolt
|
|
45
45
|
when '.ps1'
|
46
46
|
[
|
47
47
|
'powershell.exe',
|
48
|
-
[*PS_ARGS, path]
|
48
|
+
[*PS_ARGS, '-File', path]
|
49
49
|
]
|
50
50
|
when '.pp'
|
51
51
|
[
|
@@ -119,11 +119,11 @@ module Bolt
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
def
|
122
|
+
def make_tmpdir
|
123
123
|
find_parent = target.options['tmpdir'] ? "\"#{target.options['tmpdir']}\"" : '[System.IO.Path]::GetTempPath()'
|
124
|
-
result = execute(Snippets.
|
124
|
+
result = execute(Snippets.make_tmpdir(find_parent))
|
125
125
|
if result.exit_code != 0
|
126
|
-
raise Bolt::Node::FileError.new("Could not make
|
126
|
+
raise Bolt::Node::FileError.new("Could not make tmpdir: #{result.stderr.string}", 'TMPDIR_ERROR')
|
127
127
|
end
|
128
128
|
result.stdout.string.chomp
|
129
129
|
end
|
@@ -132,11 +132,21 @@ module Bolt
|
|
132
132
|
execute(Snippets.rmdir(dir))
|
133
133
|
end
|
134
134
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
135
|
+
def with_tmpdir
|
136
|
+
unless @tmpdir
|
137
|
+
# Only cleanup the directory afterward if we made it to begin with
|
138
|
+
owner = true
|
139
|
+
@tmpdir = make_tmpdir
|
140
|
+
end
|
141
|
+
yield @tmpdir
|
138
142
|
ensure
|
139
|
-
|
143
|
+
if owner && @tmpdir
|
144
|
+
if target.options['cleanup']
|
145
|
+
rmdir(@tmpdir)
|
146
|
+
else
|
147
|
+
@logger.warn("Skipping cleanup of tmpdir '#{@tmpdir}'")
|
148
|
+
end
|
149
|
+
end
|
140
150
|
end
|
141
151
|
|
142
152
|
def run_ps_task(task_path, arguments, input_method)
|
@@ -167,7 +177,7 @@ module Bolt
|
|
167
177
|
def run_script(script, arguments, _options = {})
|
168
178
|
# unpack any Sensitive data
|
169
179
|
arguments = unwrap_sensitive_args(arguments)
|
170
|
-
|
180
|
+
with_tmpdir do |dir|
|
171
181
|
script_path = write_executable(dir, script)
|
172
182
|
command = if powershell_file?(script_path)
|
173
183
|
Snippets.run_script(arguments, script_path)
|
@@ -194,7 +204,7 @@ module Bolt
|
|
194
204
|
|
195
205
|
# unpack any Sensitive data
|
196
206
|
arguments = unwrap_sensitive_args(arguments)
|
197
|
-
|
207
|
+
with_tmpdir do |dir|
|
198
208
|
if extra_files.empty?
|
199
209
|
task_dir = dir
|
200
210
|
else
|
@@ -243,14 +253,32 @@ module Bolt
|
|
243
253
|
end
|
244
254
|
|
245
255
|
def execute(command)
|
256
|
+
if conn.max_command_length && command.length > conn.max_command_length
|
257
|
+
return with_tmpdir do |dir|
|
258
|
+
command += "\r\nif (!$?) { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
259
|
+
script_file = File.join(dir, "#{SecureRandom.uuid}_wrapper.ps1")
|
260
|
+
conn.copy_file(StringIO.new(command), script_file)
|
261
|
+
args = escape_arguments([script_file])
|
262
|
+
script_invocation = ['powershell.exe', *PS_ARGS, '-File', *args].join(' ')
|
263
|
+
execute(script_invocation)
|
264
|
+
end
|
265
|
+
end
|
246
266
|
inp, out, err, t = conn.execute(command)
|
247
267
|
|
248
268
|
result = Bolt::Node::Output.new
|
249
269
|
inp.close
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
270
|
+
stdout = Thread.new do
|
271
|
+
# Set to binmode to preserve \r\n line endings, but save and restore
|
272
|
+
# the proper encoding so the string isn't later misinterpreted
|
273
|
+
encoding = out.external_encoding
|
274
|
+
out.binmode
|
275
|
+
result.stdout << out.read.force_encoding(encoding)
|
276
|
+
end
|
277
|
+
stderr = Thread.new do
|
278
|
+
encoding = err.external_encoding
|
279
|
+
err.binmode
|
280
|
+
result.stderr << err.read.force_encoding(encoding)
|
281
|
+
end
|
254
282
|
|
255
283
|
stdout.join
|
256
284
|
stderr.join
|
data/lib/bolt/target.rb
CHANGED
@@ -31,7 +31,8 @@ module Bolt
|
|
31
31
|
facts = nil,
|
32
32
|
vars = nil,
|
33
33
|
features = nil,
|
34
|
-
plugin_hooks = nil
|
34
|
+
plugin_hooks = nil,
|
35
|
+
resources = nil)
|
35
36
|
from_asserted_hash('uri' => uri)
|
36
37
|
end
|
37
38
|
# rubocop:enable Lint/UnusedMethodArgument
|
@@ -75,6 +76,16 @@ module Bolt
|
|
75
76
|
inventory_target.target_alias
|
76
77
|
end
|
77
78
|
|
79
|
+
def resources
|
80
|
+
inventory_target.resources
|
81
|
+
end
|
82
|
+
|
83
|
+
# rubocop:disable Naming/AccessorMethodName
|
84
|
+
def set_resource(resource)
|
85
|
+
inventory_target.set_resource(resource)
|
86
|
+
end
|
87
|
+
# rubocop:enable Naming/AccessorMethodName
|
88
|
+
|
78
89
|
def to_h
|
79
90
|
options.to_h.merge(
|
80
91
|
'name' => name,
|
@@ -99,7 +110,8 @@ module Bolt
|
|
99
110
|
'vars' => vars,
|
100
111
|
'features' => features,
|
101
112
|
'facts' => facts,
|
102
|
-
'plugin_hooks' => plugin_hooks
|
113
|
+
'plugin_hooks' => plugin_hooks,
|
114
|
+
'groups' => @inventory.group_names_for(name)
|
103
115
|
}
|
104
116
|
end
|
105
117
|
|
@@ -154,5 +166,9 @@ module Bolt
|
|
154
166
|
self.class.equal?(other.class) && @name == other.name
|
155
167
|
end
|
156
168
|
alias == eql?
|
169
|
+
|
170
|
+
def hash
|
171
|
+
@name.hash
|
172
|
+
end
|
157
173
|
end
|
158
174
|
end
|
data/lib/bolt/transport/base.rb
CHANGED
@@ -32,7 +32,7 @@ module Bolt
|
|
32
32
|
# Transports that need their own batching, like the Orch transport, can
|
33
33
|
# instead override the batches() method to split Targets into sets that can
|
34
34
|
# be executed together, and override the batch_task() and related methods
|
35
|
-
# to execute a batch of
|
35
|
+
# to execute a batch of targets. In that case, those Transports should accept
|
36
36
|
# a block argument and call it with a :node_start event for each Target
|
37
37
|
# before executing, and a :node_result event for each Target after
|
38
38
|
# execution.
|
@@ -90,12 +90,12 @@ module Bolt
|
|
90
90
|
# case and raises an error if it's not.
|
91
91
|
def assert_batch_size_one(method, targets)
|
92
92
|
if targets.length > 1
|
93
|
-
message = "#{self.class.name} must implement #{method} to support batches (got #{targets.length}
|
93
|
+
message = "#{self.class.name} must implement #{method} to support batches (got #{targets.length} targets)"
|
94
94
|
raise NotImplementedError, message
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
# Runs the given task on a batch of
|
98
|
+
# Runs the given task on a batch of targets.
|
99
99
|
#
|
100
100
|
# The default implementation only supports batches of size 1 and will fail otherwise.
|
101
101
|
#
|
@@ -104,12 +104,28 @@ module Bolt
|
|
104
104
|
assert_batch_size_one("batch_task()", targets)
|
105
105
|
target = targets.first
|
106
106
|
with_events(target, callback, 'task') do
|
107
|
-
@logger.debug { "Running task
|
107
|
+
@logger.debug { "Running task '#{task.name}' on #{target.safe_name}" }
|
108
108
|
run_task(target, task, arguments, options)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
# Runs the given
|
112
|
+
# Runs the given task on a batch of targets with variable parameters.
|
113
|
+
#
|
114
|
+
# The default implementation only supports batches of size 1 and will fail otherwise.
|
115
|
+
#
|
116
|
+
# Transports may override this method to implment their own batch processing.
|
117
|
+
def batch_task_with(targets, task, target_mapping, options = {}, &callback)
|
118
|
+
assert_batch_size_one("batch_task_with()", targets)
|
119
|
+
target = targets.first
|
120
|
+
arguments = target_mapping[target]
|
121
|
+
|
122
|
+
with_events(target, callback, 'task') do
|
123
|
+
@logger.debug { "Running task '#{task.name}' on #{target.safe_name} with '#{arguments.to_json}'" }
|
124
|
+
run_task(target, task, arguments, options)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Runs the given command on a batch of targets.
|
113
129
|
#
|
114
130
|
# The default implementation only supports batches of size 1 and will fail otherwise.
|
115
131
|
#
|
@@ -123,7 +139,7 @@ module Bolt
|
|
123
139
|
end
|
124
140
|
end
|
125
141
|
|
126
|
-
# Runs the given script on a batch of
|
142
|
+
# Runs the given script on a batch of targets.
|
127
143
|
#
|
128
144
|
# The default implementation only supports batches of size 1 and will fail otherwise.
|
129
145
|
#
|
@@ -137,7 +153,7 @@ module Bolt
|
|
137
153
|
end
|
138
154
|
end
|
139
155
|
|
140
|
-
# Uploads the given source file to the destination location on a batch of
|
156
|
+
# Uploads the given source file to the destination location on a batch of targets.
|
141
157
|
#
|
142
158
|
# The default implementation only supports batches of size 1 and will fail otherwise.
|
143
159
|
#
|
@@ -157,7 +173,7 @@ module Bolt
|
|
157
173
|
end
|
158
174
|
|
159
175
|
# Split the given list of targets into a list of batches. The default
|
160
|
-
# implementation returns single-
|
176
|
+
# implementation returns single-target batches.
|
161
177
|
#
|
162
178
|
# Transports may override this method, and the corresponding batch_*
|
163
179
|
# methods, to implement their own batch processing.
|
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
|
20
20
|
def upload(target, source, destination, _options = {})
|
21
21
|
with_connection(target) do |conn|
|
22
|
-
conn.
|
22
|
+
conn.with_remote_tmpdir do |dir|
|
23
23
|
basename = File.basename(destination)
|
24
24
|
tmpfile = "#{dir}/#{basename}"
|
25
25
|
if File.directory?(source)
|
@@ -57,7 +57,7 @@ module Bolt
|
|
57
57
|
arguments = unwrap_sensitive_args(arguments)
|
58
58
|
|
59
59
|
with_connection(target) do |conn|
|
60
|
-
conn.
|
60
|
+
conn.with_remote_tmpdir do |dir|
|
61
61
|
remote_path = conn.write_remote_executable(dir, script)
|
62
62
|
stdout, stderr, exitcode = conn.execute(remote_path, *arguments, {})
|
63
63
|
Bolt::Result.for_command(target, stdout, stderr, exitcode, 'script', script)
|
@@ -77,7 +77,7 @@ module Bolt
|
|
77
77
|
with_connection(target) do |conn|
|
78
78
|
execute_options = {}
|
79
79
|
execute_options[:interpreter] = select_interpreter(executable, target.options['interpreters'])
|
80
|
-
conn.
|
80
|
+
conn.with_remote_tmpdir do |dir|
|
81
81
|
if extra_files.empty?
|
82
82
|
task_dir = dir
|
83
83
|
else
|
@@ -103,25 +103,29 @@ module Bolt
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
-
def
|
106
|
+
def make_tmpdir
|
107
107
|
tmpdir = @target.options.fetch('tmpdir', container_tmpdir)
|
108
108
|
tmppath = "#{tmpdir}/#{SecureRandom.uuid}"
|
109
109
|
|
110
110
|
stdout, stderr, exitcode = execute('mkdir', '-m', '700', tmppath, {})
|
111
111
|
if exitcode != 0
|
112
|
-
raise Bolt::Node::FileError.new("Could not make
|
112
|
+
raise Bolt::Node::FileError.new("Could not make tmpdir: #{stderr}", 'TMPDIR_ERROR')
|
113
113
|
end
|
114
114
|
tmppath || stdout.first
|
115
115
|
end
|
116
116
|
|
117
|
-
def
|
118
|
-
dir =
|
117
|
+
def with_remote_tmpdir
|
118
|
+
dir = make_tmpdir
|
119
119
|
yield dir
|
120
120
|
ensure
|
121
121
|
if dir
|
122
|
-
|
123
|
-
|
124
|
-
|
122
|
+
if @target.options['cleanup']
|
123
|
+
_, stderr, exitcode = execute('rm', '-rf', dir, {})
|
124
|
+
if exitcode != 0
|
125
|
+
@logger.warn("Failed to clean up tmpdir '#{dir}': #{stderr}")
|
126
|
+
end
|
127
|
+
else
|
128
|
+
@logger.warn("Skipping cleanup of tmpdir '#{dir}'")
|
125
129
|
end
|
126
130
|
end
|
127
131
|
end
|