bolt 2.23.0 → 2.27.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 +1 -1
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +1 -1
- data/exe/bolt +1 -0
- data/guides/inventory.txt +19 -0
- data/guides/project.txt +22 -0
- data/lib/bolt/analytics.rb +11 -7
- data/lib/bolt/applicator.rb +11 -10
- data/lib/bolt/bolt_option_parser.rb +75 -13
- data/lib/bolt/catalog.rb +4 -2
- data/lib/bolt/cli.rb +156 -176
- data/lib/bolt/config.rb +55 -25
- data/lib/bolt/config/options.rb +28 -6
- data/lib/bolt/executor.rb +5 -3
- data/lib/bolt/inventory.rb +8 -1
- data/lib/bolt/inventory/group.rb +4 -4
- data/lib/bolt/inventory/inventory.rb +1 -1
- data/lib/bolt/inventory/target.rb +1 -1
- data/lib/bolt/logger.rb +12 -6
- data/lib/bolt/outputter/human.rb +10 -0
- data/lib/bolt/outputter/json.rb +11 -0
- data/lib/bolt/outputter/logger.rb +3 -3
- data/lib/bolt/outputter/rainbow.rb +15 -0
- data/lib/bolt/pal.rb +23 -12
- data/lib/bolt/pal/yaml_plan/evaluator.rb +1 -1
- data/lib/bolt/pal/yaml_plan/transpiler.rb +11 -3
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/project.rb +63 -17
- data/lib/bolt/project_migrate.rb +138 -0
- data/lib/bolt/puppetdb/client.rb +1 -1
- data/lib/bolt/puppetdb/config.rb +1 -1
- data/lib/bolt/puppetfile.rb +160 -0
- data/lib/bolt/puppetfile/installer.rb +43 -0
- data/lib/bolt/puppetfile/module.rb +66 -0
- data/lib/bolt/r10k_log_proxy.rb +1 -1
- data/lib/bolt/rerun.rb +2 -2
- data/lib/bolt/result.rb +23 -0
- data/lib/bolt/shell.rb +1 -1
- data/lib/bolt/shell/bash.rb +7 -7
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +1 -1
- data/lib/bolt/transport/docker/connection.rb +10 -10
- data/lib/bolt/transport/local/connection.rb +3 -3
- data/lib/bolt/transport/orch.rb +3 -3
- data/lib/bolt/transport/ssh.rb +1 -1
- data/lib/bolt/transport/ssh/connection.rb +6 -6
- data/lib/bolt/transport/ssh/exec_connection.rb +5 -5
- data/lib/bolt/transport/winrm.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +9 -9
- data/lib/bolt/util.rb +2 -2
- data/lib/bolt/util/puppet_log_level.rb +4 -3
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +2 -2
- data/lib/bolt_server/config.rb +1 -1
- data/lib/bolt_server/file_cache.rb +1 -1
- data/lib/bolt_server/transport_app.rb +189 -14
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/run.rb +3 -0
- metadata +12 -12
data/lib/bolt/puppetdb/client.rb
CHANGED
data/lib/bolt/puppetdb/config.rb
CHANGED
@@ -35,7 +35,7 @@ module Bolt
|
|
35
35
|
begin
|
36
36
|
config = JSON.parse(File.read(filepath)) if filepath
|
37
37
|
rescue StandardError => e
|
38
|
-
|
38
|
+
Bolt::Logger.logger(self).error("Could not load puppetdb.conf from #{filepath}: #{e.message}")
|
39
39
|
end
|
40
40
|
|
41
41
|
config = config.fetch('puppetdb', {})
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
require 'bolt/puppetfile/module'
|
5
|
+
|
6
|
+
# This class manages the logical contents of a Puppetfile. It includes methods
|
7
|
+
# for parsing a Puppetfile and its modules, resolving module dependencies,
|
8
|
+
# and writing a Puppetfile.
|
9
|
+
#
|
10
|
+
module Bolt
|
11
|
+
class Puppetfile
|
12
|
+
attr_reader :modules
|
13
|
+
|
14
|
+
def initialize(modules = [])
|
15
|
+
@modules = Set.new
|
16
|
+
add_modules(modules)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Loads a Puppetfile and parses its module specifications, returning a
|
20
|
+
# Bolt::Puppetfile object with the modules set.
|
21
|
+
#
|
22
|
+
def self.parse(path)
|
23
|
+
require 'puppetfile-resolver'
|
24
|
+
require 'puppetfile-resolver/puppetfile/parser/r10k_eval'
|
25
|
+
|
26
|
+
begin
|
27
|
+
parsed = ::PuppetfileResolver::Puppetfile::Parser::R10KEval.parse(File.read(path))
|
28
|
+
rescue StandardError => e
|
29
|
+
raise Bolt::Error.new(
|
30
|
+
"Unable to parse Puppetfile #{path}: #{e.message}",
|
31
|
+
'bolt/puppetfile-parsing'
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
unless parsed.valid?
|
36
|
+
raise Bolt::ValidationError,
|
37
|
+
"Unable to parse Puppetfile #{path}"
|
38
|
+
end
|
39
|
+
|
40
|
+
modules = parsed.modules.map do |mod|
|
41
|
+
Bolt::Puppetfile::Module.new(mod.owner, mod.name, mod.version)
|
42
|
+
end
|
43
|
+
|
44
|
+
new(modules)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Writes a Puppetfile that includes specifications for each of the
|
48
|
+
# modules.
|
49
|
+
#
|
50
|
+
def write(path, force: false)
|
51
|
+
if File.exist?(path) && !force
|
52
|
+
raise Bolt::FileError.new(
|
53
|
+
"Cannot overwrite existing Puppetfile at #{path}. To forcibly overwrite, "\
|
54
|
+
"run with the '--force' option.",
|
55
|
+
path
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
File.open(path, 'w') do |file|
|
60
|
+
file.puts '# This Puppetfile is managed by Bolt. Do not edit.'
|
61
|
+
modules.each { |mod| file.puts mod.to_spec }
|
62
|
+
file.puts
|
63
|
+
end
|
64
|
+
rescue SystemCallError => e
|
65
|
+
raise Bolt::FileError.new(
|
66
|
+
"#{e.message}: unable to write Puppetfile.",
|
67
|
+
path
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Resolves module dependencies using the puppetfile-resolver library. The
|
72
|
+
# resolver will return a document model including all module dependencies
|
73
|
+
# and the latest version that can be installed for each. The document model
|
74
|
+
# is parsed and turned into a Set of Bolt::Puppetfile::Module objects.
|
75
|
+
#
|
76
|
+
def resolve
|
77
|
+
require 'puppetfile-resolver'
|
78
|
+
|
79
|
+
# Build the document model from the modules.
|
80
|
+
model = PuppetfileResolver::Puppetfile::Document.new('')
|
81
|
+
|
82
|
+
@modules.each do |mod|
|
83
|
+
model.add_module(
|
84
|
+
PuppetfileResolver::Puppetfile::ForgeModule.new(mod.title).tap do |tap|
|
85
|
+
tap.version = :latest
|
86
|
+
end
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Make sure the Puppetfile model is valid.
|
91
|
+
unless model.valid?
|
92
|
+
raise Bolt::ValidationError,
|
93
|
+
"Unable to resolve dependencies for modules: #{@modules.map(&:title).join(', ')}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Create the resolver using the Puppetfile model. nil disables Puppet
|
97
|
+
# version restrictions.
|
98
|
+
resolver = PuppetfileResolver::Resolver.new(model, nil)
|
99
|
+
|
100
|
+
# Configure and resolve the dependency graph, catching any errors
|
101
|
+
# raised by puppetfile-resolver and re-raising them as Bolt errors.
|
102
|
+
begin
|
103
|
+
result = resolver.resolve(
|
104
|
+
cache: nil,
|
105
|
+
ui: nil,
|
106
|
+
module_paths: [],
|
107
|
+
allow_missing_modules: true
|
108
|
+
)
|
109
|
+
rescue StandardError => e
|
110
|
+
raise Bolt::Error.new(e.message, 'bolt/puppetfile-resolver-error')
|
111
|
+
end
|
112
|
+
|
113
|
+
# Validate that the modules exist.
|
114
|
+
missing_graph = result.specifications.select do |_name, spec|
|
115
|
+
spec.instance_of? PuppetfileResolver::Models::MissingModuleSpecification
|
116
|
+
end
|
117
|
+
|
118
|
+
if missing_graph.any?
|
119
|
+
titles = model.modules.each_with_object({}) do |mod, acc|
|
120
|
+
acc[mod.name] = mod.title
|
121
|
+
end
|
122
|
+
|
123
|
+
names = titles.values_at(*missing_graph.keys)
|
124
|
+
plural = names.count == 1 ? '' : 's'
|
125
|
+
|
126
|
+
raise Bolt::Error.new(
|
127
|
+
"Unknown module name#{plural} #{names.join(', ')}",
|
128
|
+
'bolt/unknown-modules'
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Filter the dependency graph to only include module specifications. This
|
133
|
+
# will only remove the Puppet version specification, which is not needed.
|
134
|
+
specs = result.specifications.select do |_name, spec|
|
135
|
+
spec.instance_of? PuppetfileResolver::Models::ModuleSpecification
|
136
|
+
end
|
137
|
+
|
138
|
+
@modules = specs.map do |_name, spec|
|
139
|
+
Bolt::Puppetfile::Module.new(spec.owner, spec.name, spec.version.to_s)
|
140
|
+
end.to_set
|
141
|
+
end
|
142
|
+
|
143
|
+
# Adds to the set of modules.
|
144
|
+
#
|
145
|
+
def add_modules(modules)
|
146
|
+
modules.each do |mod|
|
147
|
+
case mod
|
148
|
+
when Bolt::Puppetfile::Module
|
149
|
+
@modules << mod
|
150
|
+
when Hash
|
151
|
+
@modules << Bolt::Puppetfile::Module.from_hash(mod)
|
152
|
+
else
|
153
|
+
raise Bolt::ValidationError, "Module must be a Bolt::Puppetfile::Module or Hash."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
@modules
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'r10k/cli'
|
4
|
+
require 'bolt/r10k_log_proxy'
|
5
|
+
require 'bolt/error'
|
6
|
+
|
7
|
+
# This class is used to install modules from a Puppetfile to a module directory.
|
8
|
+
#
|
9
|
+
module Bolt
|
10
|
+
class Puppetfile
|
11
|
+
class Installer
|
12
|
+
def initialize(config = {})
|
13
|
+
@config = config
|
14
|
+
end
|
15
|
+
|
16
|
+
def install(path, moduledir)
|
17
|
+
unless File.exist?(path)
|
18
|
+
raise Bolt::FileError.new(
|
19
|
+
"Could not find a Puppetfile at #{path}",
|
20
|
+
path
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
r10k_opts = {
|
25
|
+
root: File.dirname(path),
|
26
|
+
puppetfile: path.to_s,
|
27
|
+
moduledir: moduledir.to_s
|
28
|
+
}
|
29
|
+
|
30
|
+
settings = R10K::Settings.global_settings.evaluate(@config)
|
31
|
+
R10K::Initializers::GlobalInitializer.new(settings).call
|
32
|
+
install_action = R10K::Action::Puppetfile::Install.new(r10k_opts, nil)
|
33
|
+
|
34
|
+
# Override the r10k logger with a proxy to our own logger
|
35
|
+
R10K::Logging.instance_variable_set(:@outputter, Bolt::R10KLogProxy.new)
|
36
|
+
|
37
|
+
install_action.call
|
38
|
+
rescue R10K::Error => e
|
39
|
+
raise PuppetfileError, e
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
|
5
|
+
# This class represents a module specification. It used by the Bolt::Puppetfile
|
6
|
+
# class to have a consistent API for accessing a module's attributes.
|
7
|
+
#
|
8
|
+
module Bolt
|
9
|
+
class Puppetfile
|
10
|
+
class Module
|
11
|
+
attr_reader :owner, :name, :version
|
12
|
+
|
13
|
+
def initialize(owner, name, version = nil)
|
14
|
+
@owner = owner
|
15
|
+
@name = name
|
16
|
+
@version = version
|
17
|
+
end
|
18
|
+
|
19
|
+
# Creates a new module from a hash.
|
20
|
+
#
|
21
|
+
def self.from_hash(mod)
|
22
|
+
unless mod['name'].is_a?(String)
|
23
|
+
raise Bolt::ValidationError,
|
24
|
+
"Module name must be a String, not #{mod['name'].inspect}"
|
25
|
+
end
|
26
|
+
|
27
|
+
owner, name = mod['name'].tr('/', '-').split('-', 2)
|
28
|
+
|
29
|
+
unless owner && name
|
30
|
+
raise Bolt::ValidationError, "Module name #{mod['name']} must include both the owner and module name."
|
31
|
+
end
|
32
|
+
|
33
|
+
new(owner, name)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the module's title.
|
37
|
+
#
|
38
|
+
def title
|
39
|
+
"#{@owner}-#{@name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Checks two modules for equality.
|
43
|
+
#
|
44
|
+
def eql?(other)
|
45
|
+
self.class == other.class && @owner == other.owner && @name == other.name
|
46
|
+
end
|
47
|
+
alias == eql?
|
48
|
+
|
49
|
+
# Hashes the module.
|
50
|
+
#
|
51
|
+
def hash
|
52
|
+
[@owner, @name].hash
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the Puppetfile specification for the module.
|
56
|
+
#
|
57
|
+
def to_spec
|
58
|
+
if @version
|
59
|
+
"mod #{title.inspect}, #{@version.inspect}"
|
60
|
+
else
|
61
|
+
"mod #{title.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/bolt/r10k_log_proxy.rb
CHANGED
data/lib/bolt/rerun.rb
CHANGED
@@ -8,7 +8,7 @@ module Bolt
|
|
8
8
|
def initialize(path, save_failures)
|
9
9
|
@path = path
|
10
10
|
@save_failures = save_failures
|
11
|
-
@logger =
|
11
|
+
@logger = Bolt::Logger.logger(self)
|
12
12
|
end
|
13
13
|
|
14
14
|
def data
|
@@ -53,7 +53,7 @@ module Bolt
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
rescue StandardError => e
|
56
|
-
|
56
|
+
Bolt::Logger.warn_once('unwriteable_file', "Failed to save result to #{@path}: #{e.message}")
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
data/lib/bolt/result.rb
CHANGED
@@ -65,6 +65,25 @@ module Bolt
|
|
65
65
|
'msg' => msg,
|
66
66
|
'details' => { 'exit_code' => exit_code } }
|
67
67
|
end
|
68
|
+
|
69
|
+
if value.key?('_error')
|
70
|
+
unless value['_error'].is_a?(Hash) && value['_error'].key?('msg')
|
71
|
+
value['_error'] = {
|
72
|
+
'msg' => "Invalid error returned from task #{task}: #{value['_error'].inspect}. Error "\
|
73
|
+
"must be an object with a msg key.",
|
74
|
+
'kind' => 'bolt/invalid-task-error',
|
75
|
+
'details' => { 'original_error' => value['_error'] }
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
value['_error']['kind'] ||= 'bolt/error'
|
80
|
+
value['_error']['details'] ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
if value.key?('_sensitive')
|
84
|
+
value['_sensitive'] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(value['_sensitive'])
|
85
|
+
end
|
86
|
+
|
68
87
|
new(target, value: value, action: 'task', object: task)
|
69
88
|
end
|
70
89
|
|
@@ -205,5 +224,9 @@ module Bolt
|
|
205
224
|
|
206
225
|
end
|
207
226
|
end
|
227
|
+
|
228
|
+
def sensitive
|
229
|
+
value['_sensitive']
|
230
|
+
end
|
208
231
|
end
|
209
232
|
end
|
data/lib/bolt/shell.rb
CHANGED
data/lib/bolt/shell/bash.rb
CHANGED
@@ -103,7 +103,7 @@ module Bolt
|
|
103
103
|
" using '#{execute_options[:interpreter]}' interpreter"
|
104
104
|
end
|
105
105
|
# log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
|
106
|
-
logger.
|
106
|
+
logger.trace("Running '#{executable}' with #{arguments.to_json}#{interpreter_debug}")
|
107
107
|
# unpack any Sensitive data
|
108
108
|
arguments = unwrap_sensitive_args(arguments)
|
109
109
|
|
@@ -203,13 +203,13 @@ module Bolt
|
|
203
203
|
|
204
204
|
def handle_sudo_errors(err)
|
205
205
|
if err =~ /^#{conn.user} is not in the sudoers file\./
|
206
|
-
@logger.
|
206
|
+
@logger.trace { err }
|
207
207
|
raise Bolt::Node::EscalateError.new(
|
208
208
|
"User #{conn.user} does not have sudo permission on #{target}",
|
209
209
|
'SUDO_DENIED'
|
210
210
|
)
|
211
211
|
elsif err =~ /^Sorry, try again\./
|
212
|
-
@logger.
|
212
|
+
@logger.trace { err }
|
213
213
|
raise Bolt::Node::EscalateError.new(
|
214
214
|
"Sudo password for user #{conn.user} not recognized on #{target}",
|
215
215
|
'BAD_PASSWORD'
|
@@ -351,7 +351,7 @@ module Bolt
|
|
351
351
|
|
352
352
|
command_str = [sudo_str, env_decl, command_str].compact.join(' ')
|
353
353
|
|
354
|
-
@logger.
|
354
|
+
@logger.trace { "Executing `#{command_str}`" }
|
355
355
|
|
356
356
|
in_buffer = if !use_sudo && options[:stdin]
|
357
357
|
String.new(options[:stdin], encoding: 'binary')
|
@@ -431,16 +431,16 @@ module Bolt
|
|
431
431
|
result_output.exit_code = t.value.respond_to?(:exitstatus) ? t.value.exitstatus : t.value
|
432
432
|
|
433
433
|
if result_output.exit_code == 0
|
434
|
-
@logger.
|
434
|
+
@logger.trace { "Command `#{command_str}` returned successfully" }
|
435
435
|
else
|
436
|
-
@logger.
|
436
|
+
@logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
|
437
437
|
end
|
438
438
|
result_output
|
439
439
|
rescue StandardError
|
440
440
|
# Ensure we close stdin and kill the child process
|
441
441
|
inp&.close
|
442
442
|
t&.terminate if t&.alive?
|
443
|
-
@logger.
|
443
|
+
@logger.trace { "Command aborted" }
|
444
444
|
raise
|
445
445
|
end
|
446
446
|
|
data/lib/bolt/task.rb
CHANGED
data/lib/bolt/transport/base.rb
CHANGED
@@ -10,9 +10,9 @@ module Bolt
|
|
10
10
|
def initialize(target)
|
11
11
|
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
12
12
|
@target = target
|
13
|
-
@logger =
|
13
|
+
@logger = Bolt::Logger.logger(target.safe_name)
|
14
14
|
@docker_host = @target.options['service-url']
|
15
|
-
@logger.
|
15
|
+
@logger.trace("Initializing docker connection to #{@target.safe_name}")
|
16
16
|
end
|
17
17
|
|
18
18
|
def connect
|
@@ -25,7 +25,7 @@ module Bolt
|
|
25
25
|
output = execute_local_docker_json_command('inspect', [output[index]["ID"]])
|
26
26
|
# Store the container information for later
|
27
27
|
@container_info = output[0]
|
28
|
-
@logger.
|
28
|
+
@logger.trace { "Opened session" }
|
29
29
|
true
|
30
30
|
rescue StandardError => e
|
31
31
|
raise Bolt::Node::ConnectError.new(
|
@@ -57,16 +57,16 @@ module Bolt
|
|
57
57
|
command_options << container_id
|
58
58
|
command_options.concat(command)
|
59
59
|
|
60
|
-
@logger.
|
60
|
+
@logger.trace { "Executing: exec #{command_options}" }
|
61
61
|
|
62
62
|
stdout_str, stderr_str, status = execute_local_docker_command('exec', command_options, options[:stdin])
|
63
63
|
|
64
64
|
# The actual result is the exitstatus not the process object
|
65
65
|
status = status.nil? ? -32768 : status.exitstatus
|
66
66
|
if status == 0
|
67
|
-
@logger.
|
67
|
+
@logger.trace { "Command returned successfully" }
|
68
68
|
else
|
69
|
-
@logger.
|
69
|
+
@logger.trace { "Command failed with exit code #{status}" }
|
70
70
|
end
|
71
71
|
stdout_str.force_encoding(Encoding::UTF_8)
|
72
72
|
stderr_str.force_encoding(Encoding::UTF_8)
|
@@ -75,12 +75,12 @@ module Bolt
|
|
75
75
|
stderr_str.gsub!("\r\n", "\n")
|
76
76
|
[stdout_str, stderr_str, status]
|
77
77
|
rescue StandardError
|
78
|
-
@logger.
|
78
|
+
@logger.trace { "Command aborted" }
|
79
79
|
raise
|
80
80
|
end
|
81
81
|
|
82
82
|
def write_remote_file(source, destination)
|
83
|
-
@logger.
|
83
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
84
84
|
_, stdout_str, status = execute_local_docker_command('cp', [source, "#{container_id}:#{destination}"])
|
85
85
|
unless status.exitstatus.zero?
|
86
86
|
raise "Error writing file to container #{@container_id}: #{stdout_str}"
|
@@ -90,7 +90,7 @@ module Bolt
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def write_remote_directory(source, destination)
|
93
|
-
@logger.
|
93
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
94
94
|
_, stdout_str, status = execute_local_docker_command('cp', [source, "#{container_id}:#{destination}"])
|
95
95
|
unless status.exitstatus.zero?
|
96
96
|
raise "Error writing directory to container #{@container_id}: #{stdout_str}"
|
@@ -100,7 +100,7 @@ module Bolt
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def download_remote_content(source, destination)
|
103
|
-
@logger.
|
103
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
104
104
|
# Create the destination directory, otherwise copying a source directory with Docker will
|
105
105
|
# copy the *contents* of the directory.
|
106
106
|
# https://docs.docker.com/engine/reference/commandline/cp/
|