bolt 1.5.0 → 1.6.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_task.rb +1 -1
- data/lib/bolt/config.rb +14 -10
- data/lib/bolt/executor.rb +10 -4
- data/lib/bolt/inventory.rb +11 -10
- data/lib/bolt/node/errors.rb +8 -1
- data/lib/bolt/target.rb +25 -2
- data/lib/bolt/task.rb +13 -2
- data/lib/bolt/task/remote.rb +25 -0
- data/lib/bolt/transport/base.rb +22 -6
- data/lib/bolt/transport/docker.rb +6 -0
- data/lib/bolt/transport/local.rb +64 -20
- data/lib/bolt/transport/powershell.rb +330 -0
- data/lib/bolt/transport/remote.rb +53 -0
- data/lib/bolt/transport/ssh.rb +1 -2
- data/lib/bolt/transport/winrm.rb +16 -89
- data/lib/bolt/transport/winrm/connection.rb +5 -216
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/file_cache.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 557353adda3a863e4f748933cb24860616848d1696d9f0914be23474616f43ca
|
4
|
+
data.tar.gz: 91dc4d72ba25e2e827c5bf170574bedef50c744a4e31ac48684699ff59cdf753
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a4c8b39f2c353498168cf89a5e70f7b4699e6332e2826efd24a905d94ca7b52ec76a6db98e94f83fe5f7fce4b6c7f58cbc51b56e79b3fce3acf0f014f2669f8
|
7
|
+
data.tar.gz: 6bf22f4aaef6a2741b64d77b900c9a85fd3c3588feb4a071d582415afbc5ecc479048ba7aea9912131c383d5ec2e3966682f5ea8a3cade87722a927d12275c7e
|
@@ -99,7 +99,7 @@ Puppet::Functions.create_function(:run_task) do
|
|
99
99
|
options['_description'] = description if description
|
100
100
|
|
101
101
|
# Don't bother loading the local task definition if all targets use the 'pcp' transport.
|
102
|
-
if !targets.empty? && targets.all? { |t| t.
|
102
|
+
if !targets.empty? && targets.all? { |t| t.transport == 'pcp' }
|
103
103
|
# create a fake task
|
104
104
|
task = Bolt::Task.new(name: task_name, files: [{ 'name' => '', 'path' => '' }])
|
105
105
|
else
|
data/lib/bolt/config.rb
CHANGED
@@ -10,6 +10,7 @@ require 'bolt/transport/winrm'
|
|
10
10
|
require 'bolt/transport/orch'
|
11
11
|
require 'bolt/transport/local'
|
12
12
|
require 'bolt/transport/docker'
|
13
|
+
require 'bolt/transport/remote'
|
13
14
|
|
14
15
|
module Bolt
|
15
16
|
TRANSPORTS = {
|
@@ -17,7 +18,8 @@ module Bolt
|
|
17
18
|
winrm: Bolt::Transport::WinRM,
|
18
19
|
pcp: Bolt::Transport::Orch,
|
19
20
|
local: Bolt::Transport::Local,
|
20
|
-
docker: Bolt::Transport::Docker
|
21
|
+
docker: Bolt::Transport::Docker,
|
22
|
+
remote: Bolt::Transport::Remote
|
21
23
|
}.freeze
|
22
24
|
|
23
25
|
class UnknownTransportError < Bolt::Error
|
@@ -36,16 +38,15 @@ module Bolt
|
|
36
38
|
private-key tty tmpdir user connect-timeout
|
37
39
|
cacert token-file service-url].freeze
|
38
40
|
|
39
|
-
|
40
|
-
'connect-timeout' => 10,
|
41
|
-
'tty' => false
|
42
|
-
}.freeze
|
43
|
-
|
41
|
+
# TODO: move these to the transport themselves
|
44
42
|
TRANSPORT_SPECIFIC_DEFAULTS = {
|
45
43
|
ssh: {
|
46
|
-
'
|
44
|
+
'connect-timeout' => 10,
|
45
|
+
'host-key-check' => true,
|
46
|
+
'tty' => false
|
47
47
|
},
|
48
48
|
winrm: {
|
49
|
+
'connect-timeout' => 10,
|
49
50
|
'ssl' => true,
|
50
51
|
'ssl-verify' => true
|
51
52
|
},
|
@@ -53,7 +54,10 @@ module Bolt
|
|
53
54
|
'task-environment' => 'production'
|
54
55
|
},
|
55
56
|
local: {},
|
56
|
-
docker: {}
|
57
|
+
docker: {},
|
58
|
+
remote: {
|
59
|
+
'run-on' => 'localhost'
|
60
|
+
}
|
57
61
|
}.freeze
|
58
62
|
|
59
63
|
def self.default
|
@@ -88,7 +92,7 @@ module Bolt
|
|
88
92
|
|
89
93
|
@transports = {}
|
90
94
|
TRANSPORTS.each_key do |transport|
|
91
|
-
@transports[transport] =
|
95
|
+
@transports[transport] = TRANSPORT_SPECIFIC_DEFAULTS[transport].dup
|
92
96
|
end
|
93
97
|
|
94
98
|
update_from_file(config_data)
|
@@ -158,7 +162,7 @@ module Bolt
|
|
158
162
|
|
159
163
|
TRANSPORTS.each do |key, impl|
|
160
164
|
if data[key.to_s]
|
161
|
-
selected = data[key.to_s]
|
165
|
+
selected = impl.filter_options(data[key.to_s])
|
162
166
|
@transports[key].merge!(selected)
|
163
167
|
end
|
164
168
|
end
|
data/lib/bolt/executor.rb
CHANGED
@@ -32,9 +32,15 @@ module Bolt
|
|
32
32
|
@load_config = load_config
|
33
33
|
|
34
34
|
@transports = Bolt::TRANSPORTS.each_with_object({}) do |(key, val), coll|
|
35
|
-
coll[key.to_s] =
|
36
|
-
|
37
|
-
|
35
|
+
coll[key.to_s] = if key == :remote
|
36
|
+
Concurrent::Delay.new do
|
37
|
+
val.new(self)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
Concurrent::Delay.new do
|
41
|
+
val.new
|
42
|
+
end
|
43
|
+
end
|
38
44
|
end
|
39
45
|
@reported_transports = Set.new
|
40
46
|
|
@@ -64,7 +70,7 @@ module Bolt
|
|
64
70
|
# defined by the transport. Yields each batch, along with the corresponding
|
65
71
|
# transport, to the block in turn and returns an array of result promises.
|
66
72
|
def queue_execute(targets)
|
67
|
-
targets.group_by(&:
|
73
|
+
targets.group_by(&:transport).flat_map do |protocol, protocol_targets|
|
68
74
|
transport = transport(protocol)
|
69
75
|
report_transport(transport, protocol_targets.count)
|
70
76
|
transport.batches(protocol_targets).flat_map do |batch|
|
data/lib/bolt/inventory.rb
CHANGED
@@ -167,19 +167,17 @@ module Bolt
|
|
167
167
|
# Should this reconfigure configured targets?
|
168
168
|
def update_target(target)
|
169
169
|
data = @groups.data_for(target.name)
|
170
|
-
|
171
|
-
unless data
|
172
|
-
data = {}
|
173
|
-
unless Bolt::Util.windows?
|
174
|
-
data['config'] = { 'transport' => 'local' } if target.name == 'localhost'
|
175
|
-
end
|
176
|
-
end
|
170
|
+
data ||= {}
|
177
171
|
|
178
172
|
unless data['config']
|
179
173
|
@logger.debug("Did not find config for #{target.name} in inventory")
|
180
174
|
data['config'] = {}
|
181
175
|
end
|
182
176
|
|
177
|
+
unless data['config']['transport']
|
178
|
+
data['config']['transport'] = 'local' if target.name == 'localhost'
|
179
|
+
end
|
180
|
+
|
183
181
|
# These should only get set from the inventory if they have not yet
|
184
182
|
# been instantiated
|
185
183
|
set_vars_from_hash(target.name, data['vars']) unless @target_vars[target.name]
|
@@ -191,11 +189,13 @@ module Bolt
|
|
191
189
|
conf.update_from_inventory(data['config'])
|
192
190
|
conf.validate
|
193
191
|
|
194
|
-
|
195
|
-
|
192
|
+
target.update_conf(conf.transport_conf)
|
193
|
+
|
194
|
+
unless target.transport.nil? || Bolt::TRANSPORTS.include?(target.transport.to_sym)
|
195
|
+
raise Bolt::UnknownTransportError.new(target.transport, target.uri)
|
196
196
|
end
|
197
197
|
|
198
|
-
target
|
198
|
+
target
|
199
199
|
end
|
200
200
|
private :update_target
|
201
201
|
|
@@ -226,6 +226,7 @@ module Bolt
|
|
226
226
|
|
227
227
|
def expand_targets(targets)
|
228
228
|
if targets.is_a? Bolt::Target
|
229
|
+
targets.inventory = self
|
229
230
|
targets
|
230
231
|
elsif targets.is_a? Array
|
231
232
|
targets.map { |tish| expand_targets(tish) }
|
data/lib/bolt/node/errors.rb
CHANGED
@@ -7,7 +7,8 @@ module Bolt
|
|
7
7
|
class BaseError < Bolt::Error
|
8
8
|
attr_reader :issue_code
|
9
9
|
|
10
|
-
|
10
|
+
# TODO: can we just drop issue code here?
|
11
|
+
def initialize(message, issue_code = nil)
|
11
12
|
super(message, kind, nil, issue_code)
|
12
13
|
end
|
13
14
|
|
@@ -34,6 +35,12 @@ module Bolt
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
38
|
+
class RemoteError < BaseError
|
39
|
+
def kind
|
40
|
+
'puppetlabs.tasks/remote-task-error'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
37
44
|
class EnvironmentVarError < BaseError
|
38
45
|
def initialize(var, val)
|
39
46
|
message = "Could not set environment variable '#{var}' to '#{val}'"
|
data/lib/bolt/target.rb
CHANGED
@@ -6,7 +6,9 @@ require 'bolt/error'
|
|
6
6
|
module Bolt
|
7
7
|
class Target
|
8
8
|
attr_reader :uri, :options
|
9
|
-
|
9
|
+
# CODEREVIEW: this feels wrong. The altertative is threading inventory through the
|
10
|
+
# executor to the RemoteTransport
|
11
|
+
attr_accessor :inventory
|
10
12
|
|
11
13
|
PRINT_OPTS ||= %w[host user port protocol].freeze
|
12
14
|
|
@@ -41,7 +43,7 @@ module Bolt
|
|
41
43
|
def update_conf(conf)
|
42
44
|
@protocol = conf[:transport]
|
43
45
|
|
44
|
-
t_conf = conf[:transports][
|
46
|
+
t_conf = conf[:transports][transport.to_sym] || {}
|
45
47
|
# Override url methods
|
46
48
|
@user = t_conf['user']
|
47
49
|
@password = t_conf['password']
|
@@ -85,6 +87,18 @@ module Bolt
|
|
85
87
|
"Target('#{@uri}', #{opts})"
|
86
88
|
end
|
87
89
|
|
90
|
+
def to_h
|
91
|
+
options.merge(
|
92
|
+
'name' => name,
|
93
|
+
'uri' => uri,
|
94
|
+
'protocol' => protocol,
|
95
|
+
'user' => user,
|
96
|
+
'password' => password,
|
97
|
+
'host' => host,
|
98
|
+
'port' => port
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
88
102
|
def host
|
89
103
|
@uri_obj.hostname
|
90
104
|
end
|
@@ -95,10 +109,19 @@ module Bolt
|
|
95
109
|
uri
|
96
110
|
end
|
97
111
|
|
112
|
+
def remote?
|
113
|
+
@uri_obj.scheme == 'remote' || @protocol == 'remote'
|
114
|
+
end
|
115
|
+
|
98
116
|
def port
|
99
117
|
@uri_obj.port || @port
|
100
118
|
end
|
101
119
|
|
120
|
+
# transport is separate from protocol for remote targets.
|
121
|
+
def transport
|
122
|
+
remote? ? 'remote' : protocol
|
123
|
+
end
|
124
|
+
|
102
125
|
def protocol
|
103
126
|
@uri_obj.scheme || @protocol
|
104
127
|
end
|
data/lib/bolt/task.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Bolt
|
4
|
+
class NoImplementationError < Bolt::Error
|
5
|
+
def initialize(target, task)
|
6
|
+
msg = "No suitable implementation of #{task.name} for #{target.name}"
|
7
|
+
super(msg, 'bolt/no-implementation')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
# Represents a Task.
|
5
12
|
# @file and @files are mutually exclusive.
|
6
13
|
# @name [String] name of the task
|
@@ -51,13 +58,17 @@ module Bolt
|
|
51
58
|
file_map[file_name]['path']
|
52
59
|
end
|
53
60
|
|
61
|
+
def implementations
|
62
|
+
metadata['implementations']
|
63
|
+
end
|
64
|
+
|
54
65
|
# Returns a hash of implementation name, path to executable, input method (if defined),
|
55
66
|
# and any additional files (name and path)
|
56
67
|
def select_implementation(target, additional_features = [])
|
57
|
-
impl = if (impls =
|
68
|
+
impl = if (impls = implementations)
|
58
69
|
available_features = target.features + additional_features
|
59
70
|
impl = impls.find { |imp| Set.new(imp['requirements']).subset?(available_features) }
|
60
|
-
raise
|
71
|
+
raise NoImplementationError.new(target, self) unless impl
|
61
72
|
impl = impl.dup
|
62
73
|
impl['path'] = file_path(impl['name'])
|
63
74
|
impl.delete('requirements')
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/task'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class Task
|
7
|
+
class Remote < Task
|
8
|
+
def self.from_task(task)
|
9
|
+
new(task.name, task.file, task.files, task.metadata)
|
10
|
+
end
|
11
|
+
|
12
|
+
def implementations
|
13
|
+
metadata['implementations']&.select { |i| i['remote'] || metadata['remote'] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def select_implementation(target, *args)
|
17
|
+
unless implementations || metadata['remote']
|
18
|
+
raise NoImplementationError.new(target, self)
|
19
|
+
end
|
20
|
+
|
21
|
+
super(target, *args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/bolt/transport/base.rb
CHANGED
@@ -44,7 +44,12 @@ module Bolt
|
|
44
44
|
|
45
45
|
# Returns options this transport supports
|
46
46
|
def self.options
|
47
|
-
raise NotImplementedError,
|
47
|
+
raise NotImplementedError,
|
48
|
+
"self.options() or self.filter_options(unfiltered) must be implemented by the transport class"
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.filter_options(unfiltered)
|
52
|
+
unfiltered.select { |k| options.include?(k) }
|
48
53
|
end
|
49
54
|
|
50
55
|
def self.validate(_options)
|
@@ -72,13 +77,24 @@ module Bolt
|
|
72
77
|
[]
|
73
78
|
end
|
74
79
|
|
75
|
-
def
|
80
|
+
def default_input_method(_executable)
|
81
|
+
'both'
|
82
|
+
end
|
83
|
+
|
84
|
+
def select_implementation(target, task)
|
85
|
+
impl = task.select_implementation(target, provided_features)
|
86
|
+
impl['input_method'] ||= default_input_method(impl['path'])
|
87
|
+
impl
|
88
|
+
end
|
89
|
+
|
90
|
+
def reject_transport_options(target, options)
|
76
91
|
if target.options['run-as']
|
77
92
|
options.reject { |k, _v| k == '_run_as' }
|
78
93
|
else
|
79
94
|
options
|
80
95
|
end
|
81
96
|
end
|
97
|
+
private :reject_transport_options
|
82
98
|
|
83
99
|
# Transform a parameter map to an environment variable map, with parameter names prefixed
|
84
100
|
# with 'PT_' and values transformed to JSON unless they're strings.
|
@@ -111,7 +127,7 @@ module Bolt
|
|
111
127
|
target = targets.first
|
112
128
|
with_events(target, callback) do
|
113
129
|
@logger.debug { "Running task run '#{task}' on #{target.uri}" }
|
114
|
-
run_task(target, task, arguments,
|
130
|
+
run_task(target, task, arguments, reject_transport_options(target, options))
|
115
131
|
end
|
116
132
|
end
|
117
133
|
|
@@ -125,7 +141,7 @@ module Bolt
|
|
125
141
|
target = targets.first
|
126
142
|
with_events(target, callback) do
|
127
143
|
@logger.debug("Running command '#{command}' on #{target.uri}")
|
128
|
-
run_command(target, command,
|
144
|
+
run_command(target, command, reject_transport_options(target, options))
|
129
145
|
end
|
130
146
|
end
|
131
147
|
|
@@ -139,7 +155,7 @@ module Bolt
|
|
139
155
|
target = targets.first
|
140
156
|
with_events(target, callback) do
|
141
157
|
@logger.debug { "Running script '#{script}' on #{target.uri}" }
|
142
|
-
run_script(target, script, arguments,
|
158
|
+
run_script(target, script, arguments, reject_transport_options(target, options))
|
143
159
|
end
|
144
160
|
end
|
145
161
|
|
@@ -153,7 +169,7 @@ module Bolt
|
|
153
169
|
target = targets.first
|
154
170
|
with_events(target, callback) do
|
155
171
|
@logger.debug { "Uploading: '#{source}' to #{destination} on #{target.uri}" }
|
156
|
-
upload(target, source, destination,
|
172
|
+
upload(target, source, destination, reject_transport_options(target, options))
|
157
173
|
end
|
158
174
|
end
|
159
175
|
|
data/lib/bolt/transport/local.rb
CHANGED
@@ -4,6 +4,7 @@ require 'json'
|
|
4
4
|
require 'fileutils'
|
5
5
|
require 'tmpdir'
|
6
6
|
require 'bolt/transport/base'
|
7
|
+
require 'bolt/transport/powershell'
|
7
8
|
require 'bolt/util'
|
8
9
|
|
9
10
|
module Bolt
|
@@ -14,19 +15,23 @@ module Bolt
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def provided_features
|
17
|
-
|
18
|
+
if Bolt::Util.windows?
|
19
|
+
['powershell']
|
20
|
+
else
|
21
|
+
['shell']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_input_method(executable)
|
26
|
+
input_method ||= Powershell.powershell_file?(executable) ? 'powershell' : 'both'
|
27
|
+
input_method
|
18
28
|
end
|
19
29
|
|
20
30
|
def self.validate(_options); end
|
21
31
|
|
22
32
|
def initialize
|
23
33
|
super
|
24
|
-
|
25
|
-
if Bolt::Util.windows?
|
26
|
-
raise NotImplementedError, "The local transport is not yet implemented on Windows"
|
27
|
-
else
|
28
|
-
@conn = Shell.new
|
29
|
-
end
|
34
|
+
@conn = Shell.new
|
30
35
|
end
|
31
36
|
|
32
37
|
def in_tmpdir(base)
|
@@ -73,20 +78,32 @@ module Bolt
|
|
73
78
|
|
74
79
|
# unpack any Sensitive data AFTER we log
|
75
80
|
arguments = unwrap_sensitive_args(arguments)
|
76
|
-
if
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
if Bolt::Util.windows?
|
82
|
+
if Powershell.powershell_file?(file)
|
83
|
+
command = Powershell.run_script(arguments, file)
|
84
|
+
output = @conn.execute(command, dir: dir, env: "powershell.exe")
|
85
|
+
else
|
86
|
+
path, args = *Powershell.process_from_extension(file)
|
87
|
+
args += Powershell.escape_arguments(arguments)
|
88
|
+
command = args.unshift(path).join(' ')
|
89
|
+
output = @conn.execute(command, dir: dir)
|
90
|
+
end
|
91
|
+
else
|
92
|
+
if arguments.empty?
|
93
|
+
# We will always provide separated arguments, so work-around Open3's handling of a single
|
94
|
+
# argument as the entire command string for script paths containing spaces.
|
95
|
+
arguments = ['']
|
96
|
+
end
|
97
|
+
output = @conn.execute(file, *arguments, dir: dir)
|
80
98
|
end
|
81
|
-
output = @conn.execute(file, *arguments, dir: dir)
|
82
99
|
Bolt::Result.for_command(target, output.stdout.string, output.stderr.string, output.exit_code)
|
83
100
|
end
|
84
101
|
end
|
85
102
|
|
86
103
|
def run_task(target, task, arguments, _options = {})
|
87
|
-
implementation =
|
104
|
+
implementation = select_implementation(target, task)
|
88
105
|
executable = implementation['path']
|
89
|
-
input_method = implementation['input_method']
|
106
|
+
input_method = implementation['input_method']
|
90
107
|
extra_files = implementation['files']
|
91
108
|
|
92
109
|
in_tmpdir(target.options['tmpdir']) do |dir|
|
@@ -108,16 +125,43 @@ module Bolt
|
|
108
125
|
copy_file(executable, script)
|
109
126
|
File.chmod(0o750, script)
|
110
127
|
|
111
|
-
#
|
112
|
-
#
|
128
|
+
# log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
|
129
|
+
logger.debug("Running '#{script}' with #{arguments}")
|
113
130
|
unwrapped_arguments = unwrap_sensitive_args(arguments)
|
131
|
+
|
114
132
|
stdin = STDIN_METHODS.include?(input_method) ? JSON.dump(unwrapped_arguments) : nil
|
115
|
-
env = ENVIRONMENT_METHODS.include?(input_method) ? envify_params(unwrapped_arguments) : nil
|
116
133
|
|
117
|
-
|
118
|
-
|
134
|
+
if Bolt::Util.windows?
|
135
|
+
# WINDOWS
|
136
|
+
if ENVIRONMENT_METHODS.include?(input_method)
|
137
|
+
environment_params = envify_params(unwrapped_arguments).each_with_object([]) do |(arg, val), list|
|
138
|
+
list << Powershell.set_env(arg, val)
|
139
|
+
end
|
140
|
+
environment_params = environment_params.join("\n") + "\n"
|
141
|
+
else
|
142
|
+
environment_params = ""
|
143
|
+
end
|
119
144
|
|
120
|
-
|
145
|
+
output =
|
146
|
+
if Powershell.powershell_file?(script) && stdin.nil?
|
147
|
+
command = Powershell.run_ps_task(arguments, script, input_method)
|
148
|
+
command = environment_params + Powershell.shell_init + command
|
149
|
+
if input_method == 'powershell'
|
150
|
+
@conn.execute(command, dir: dir, env: "powershell.exe")
|
151
|
+
else
|
152
|
+
@conn.execute(command, dir: dir, stdin: stdin, env: "powershell.exe")
|
153
|
+
end
|
154
|
+
else
|
155
|
+
path, args = *Powershell.process_from_extension(script)
|
156
|
+
command = args.unshift(path).join(' ')
|
157
|
+
command = environment_params + Powershell.shell_init + command
|
158
|
+
@conn.execute(command, dir: dir, stdin: stdin, env: "powershell.exe")
|
159
|
+
end
|
160
|
+
else
|
161
|
+
# POSIX
|
162
|
+
env = ENVIRONMENT_METHODS.include?(input_method) ? envify_params(unwrapped_arguments) : nil
|
163
|
+
output = @conn.execute(script, stdin: stdin, env: env, dir: dir)
|
164
|
+
end
|
121
165
|
Bolt::Result.for_task(target, output.stdout.string, output.stderr.string, output.exit_code)
|
122
166
|
end
|
123
167
|
end
|