module Specinfra::Backend::DockerLxc::ShellHelpers
Helpers to work with the shell and with `sudo`.
Uses the following `Specinfra` configuration options:
-
`:sudo_options`: Sudo command argument list as string or as array.
-
`:sudo_path`: Sudo binary directory.
-
`:sudo_password`
-
`:disable_sudo`: whether to disable Sudo (enabled by default).
Based on the official `Specinfra::Backend::Ssh` code.
@example
class MyBackend < Specinfra::Backend::Base include Specinfra::Backend::DockerLxc::ShellHelpers def my_backend_run! stdout, stderr, status = shell_command!('uname -a') CommandResult.new( stdout: stdout, stderr: stderr, exit_status: status ) end end
Protected Instance Methods
Returns the Sudo program arguments to use by default.
@return [String] the arguments properly escaped. @example
default_sudo_args #=> "" default_sudo_args #=> "-S -p Password:\\ "
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 86 def default_sudo_args args = [] args += ['-S', '-p', sudo_prompt] if sudo_password? args.shelljoin end
Escapes a shell command.
It only escapes it when passed as array.
@param cmd [Array<String>, String] the command. @return [String] the command escaped. @example
escape_command(['sudo', '-p', 'Password: ') #=> "sudo -p Password:\\ " escape_command('uname -a') #=> "uname -a"
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 158 def escape_command(cmd) return cmd if cmd.is_a?(String) cmd.shelljoin end
Generates the command to run including the Sudo prefix if configured.
The command needs to be escaped only if passed as string.
@param cmd [Array<String>, String] the command. @return [String] the command escaped. @example
generate_escaped_command('uname -a') #=> "sudo uname -a" set :sudo_password, 'y0mVT1CYM0uRiHxjLfNV' generate_escaped_command('uname -a') #=> "sudo -p Password:\\ uname -a" set :disable_sudo, true generate_escaped_command('uname -a') #=> "uname -a"
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 176 def generate_escaped_command(cmd) if sudo? sudo_command(escape_command(cmd)) else escape_command(cmd) end end
Runs a command, including Sudo if required.
If the command is passed as string, must be properly escaped.
@param cmd [Array<String>, String] the command. @return [Array<String, Fixnum>] the array contents: stdout, stderr
and the *exit status*.
@example
shell_command!('id') #=> ["", "uid=0(root) gid=0(root) groups=0(root)\n", 0]
@api public
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 211 def shell_command!(cmd, opts = {}) cmd_escaped = generate_escaped_command(cmd) Open3.popen3(cmd_escaped, opts) do |stdin, stdout, stderr, wait_thr| read = write_sudo_password(stdin, stderr) stdin.close [stdout.read, read + stderr.read, wait_thr.value.exitstatus] end end
Checks if we need to use Sudo.
@return [TrueClass, FalseClass] whether we need to use Sudo. @example
sudo? #=> true set :disable_sudo, true sudo? #=> false
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 143 def sudo? disable_sudo = Specinfra.configuration.disable_sudo Etc.getlogin != 'root' && !disable_sudo end
Returns the Sudo program arguments.
Includes both the default and the arguments configured using `set`.
@return [String] the arguments properly escaped. @example
set :sudo_options, '-a -b -c' sudo_args #=> "-S -p Password:\\ -a -b -c"
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 100 def sudo_args sudo_options = Specinfra.configuration.sudo_options if sudo_options sudo_options = sudo_options.shelljoin if sudo_options.is_a?(Array) "#{default_sudo_args} #{sudo_options}" else default_sudo_args end end
Gets the Sudo binary path.
@return [String] the Sudo binary. @example
sudo_bin #=> "sudo" set :sudo_path, '/opt/sudo/bin' sudo_bin #=> "/opt/sudo/bin/sudo"
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 117 def sudo_bin sudo_path = Specinfra.configuration.sudo_path sudo_bin = sudo_path ? "#{sudo_path}/sudo" : 'sudo' sudo_bin.shellescape end
Adds Sudo to a command.
@param cmd_str [String] the command to run. Must be escaped. @return [String] the command escaped and including `sudo`. @example
set :sudo_password, 'y0mVT1CYM0uRiHxjLfNV' sudo_command('uname -a') #=> "sudo -S -p Password:\\ -- uname -a" set :disable_sudo, true sudo_command('uname -a') #=> "uname -a"
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 132 def sudo_command(cmd_str) "#{sudo_bin} #{sudo_args} -- #{cmd_str}" end
Reads the `:sudo_password` configuration option.
@return [String] the password. @example
set :sudo_password, 'y0mVT1CYM0uRiHxjLfNV' sudo_password #=> "y0mVT1CYM0uRiHxjLfNV"
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 67 def sudo_password Specinfra.configuration.sudo_password end
Whether the `:sudo_password` is configured.
@return [TrueClass, FalseClass] true if password is configured. @example
sudo_password? #=> false
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 76 def sudo_password? sudo_password ? true : false end
Returns the prompt used by Sudo to ask for the password.
@return [String] the prompt. @example
sudo_prompt #=> "Password: "
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 57 def sudo_prompt 'Password: ' end
Writes the password to the stdin when asked on stderr.
@param stdin [IO] stdin file descriptor. @param stderr [IO] stderr file descriptor. @return [String] the string read from stderr without including the
password prompt.
@example
write_sudo_password(stdin, stderr) #=> ""
# File lib/specinfra/backend/docker_lxc/shell_helpers.rb, line 192 def write_sudo_password(stdin, stderr) return '' unless sudo_password? read = stderr.gets(sudo_prompt.length) return read.to_s unless read == sudo_prompt stdin.puts "#{sudo_password}\n" '' end