lib/bolt/shell/bash.rb in bolt-2.16.0 vs lib/bolt/shell/bash.rb in bolt-2.17.0
- old
+ new
@@ -21,11 +21,11 @@
['shell']
end
def run_command(command, options = {})
running_as(options[:run_as]) do
- output = execute(command, sudoable: true)
+ output = execute(command, environment: options[:env_vars], sudoable: true)
Bolt::Result.for_command(target,
output.stdout.string,
output.stderr.string,
output.exit_code,
'command', command)
@@ -56,11 +56,11 @@
running_as(options[:run_as]) do
with_tmpdir do |dir|
path = write_executable(dir.to_s, script)
dir.chown(run_as)
- output = execute([path, *arguments], sudoable: true)
+ output = execute([path, *arguments], environment: options[:env_vars], sudoable: true)
Bolt::Result.for_command(target,
output.stdout.string,
output.stderr.string,
output.exit_code,
'script', script)
@@ -168,11 +168,11 @@
# See if there's a sudo prompt in the output
# If not, return the output
def check_sudo(out, inp, stdin)
buffer = out.readpartial(CHUNK_SIZE)
# Split on newlines, including the newline
- lines = buffer.split(/(?<=[\n])/)
+ lines = buffer.split(/(?<=\n)/)
# handle_sudo will return the line if it is not a sudo prompt or error
lines.map! { |line| handle_sudo(inp, line, stdin) }
lines.join("")
# If stream has reached EOF, no password prompt is expected
# return an empty string
@@ -275,37 +275,14 @@
@logger.warn("Skipping cleanup of tmpdir #{dir}")
end
end
end
- # In the case where a task is run with elevated privilege and needs stdin
- # a random string is echoed to stderr indicating that the stdin is available
- # for task input data because the sudo password has already either been
- # provided on stdin or was not needed.
- def prepend_sudo_success(sudo_id, command_str)
- command_str = "cd; #{command_str}" if conn.reset_cwd?
- "sh -c #{Shellwords.shellescape("echo #{sudo_id} 1>&2; #{command_str}")}"
+ def sudo_success(sudo_id)
+ "echo #{sudo_id} 1>&2"
end
- def prepend_chdir(command_str)
- "sh -c #{Shellwords.shellescape("cd; #{command_str}")}"
- end
-
- # A helper to build up a single string that contains all of the options for
- # privilege escalation. A wrapper script is used to direct task input to stdin
- # when a tty is allocated and thus we do not need to prepend_sudo_success when
- # using the wrapper or when the task does not require stdin data.
- def build_sudoable_command_str(command_str, sudo_str, sudo_id, options)
- if options[:stdin] && !options[:wrapper]
- "#{sudo_str} #{prepend_sudo_success(sudo_id, command_str)}"
- elsif conn.reset_cwd?
- "#{sudo_str} #{prepend_chdir(command_str)}"
- else
- "#{sudo_str} #{command_str}"
- end
- end
-
# Returns string with the interpreter conditionally prepended
def inject_interpreter(interpreter, command)
if interpreter
if command.is_a?(Array)
command.unshift(interpreter)
@@ -320,17 +297,19 @@
def execute(command, sudoable: false, **options)
run_as = options[:run_as] || self.run_as
escalate = sudoable && run_as && conn.user != run_as
use_sudo = escalate && @target.options['run-as-command'].nil?
- command_str = inject_interpreter(options[:interpreter], command)
+ # Depending on the transport, whether we're using sudo and whether
+ # there are environment variables to set, we may need to stitch
+ # together multiple commands into a single sh invocation
+ commands = [inject_interpreter(options[:interpreter], command)]
if options[:environment]
- env_decls = options[:environment].map do |env, val|
+ env_decl = options[:environment].map do |env, val|
"#{env}=#{Shellwords.shellescape(val)}"
- end
- command_str = "#{env_decls.join(' ')} #{command_str}"
+ end.join(' ')
end
if escalate
sudo_str = if use_sudo
sudo_exec = target.options['sudo-executable'] || "sudo"
@@ -338,11 +317,20 @@
sudo_flags += ["-E"] if options[:environment]
Shellwords.shelljoin(sudo_flags)
else
Shellwords.shelljoin(@target.options['run-as-command'] + [run_as])
end
- command_str = build_sudoable_command_str(command_str, sudo_str, @sudo_id, options)
+ commands.unshift('cd') if conn.reset_cwd?
+ commands.unshift(sudo_success(@sudo_id)) if options[:stdin] && !options[:wrapper]
end
+
+ command_str = if sudo_str || env_decl
+ "sh -c #{Shellwords.shellescape(commands.join('; '))}"
+ else
+ commands.last
+ end
+
+ command_str = [sudo_str, env_decl, command_str].compact.join(' ')
@logger.debug { "Executing: #{command_str}" }
in_buffer = if !use_sudo && options[:stdin]
String.new(options[:stdin], encoding: 'binary')