class SSHKit::Backend::SudoNetssh
Values that are static, like the filtered logging patterns, or the name of the env variables, can be implemented, if needed, as Configuration attributes.
Constants
- PASSWORD_PROMPT_REGEX
- SKIP_STDOUT_LOGGING_PATTERNS
Public Class Methods
config()
click to toggle source
It's not possible to send a custom configuration class, so we need to create a custom one. The :owner could be an instance variable, but it's a bit ugly to use a different setting strategy.
# File lib/sshkit/sudo/sudo_netssh.rb, line 31 def config @config ||= Class.new(Netssh::Configuration) do attr_accessor :owner, :servers_password, :commands_log end.new end
new(*args, &block)
click to toggle source
Calls superclass method
# File lib/sshkit/sudo/sudo_netssh.rb, line 38 def initialize(*args, &block) super @interaction_handler = SSHKit::Sudo::PasswordSendingInteractionHandler.new(self.class.config.servers_password + "\n") end
pool()
click to toggle source
`pool` is a class-level instance variable, so we can't use the superclass' attr_accessor. The attribute is only read though, so we don't need to handle assignments.
# File lib/sshkit/sudo/sudo_netssh.rb, line 23 def pool self.superclass.pool end
Public Instance Methods
capture(*args)
click to toggle source
Calls superclass method
# File lib/sshkit/sudo/sudo_netssh.rb, line 44 def capture(*args) # To ensure that we clean out the sudo part when the results are returned, # otherwise the commands will be corrupt. # super.gsub(PASSWORD_PROMPT_REGEX, '') end
upload!(local, remote, options = {})
click to toggle source
Required because the uploaded file is owned by the SSH user, not the owner.
Calls superclass method
# File lib/sshkit/sudo/sudo_netssh.rb, line 53 def upload!(local, remote, options = {}) super # We can't check the user inside the :as block, because @user is root. # target_user = @user || self.class.config.owner as :root do execute :chown, target_user, remote end end
Private Instance Methods
command(args, options)
click to toggle source
# File lib/sshkit/sudo/sudo_netssh.rb, line 67 def command(args, options) options[:interaction_handler] ||= @interaction_handler env = (@env || {}) user = @user || self.class.config.owner # As general Linux practice, switching user is not enough - some variables need to be updated # as well. # For an explanation, see https://saveriomiroddi.github.io/Chef-properly-run-a-resource-as-alternate-user. # user_home = user == 'root' ? '/root' : "/home/#{user}" env = env.merge(user: user, home: user_home) # Sshkit::Command#user runs commands in a non-login shell, so that variables are not inherited. # We can workaround this by setting them in the env, which is `export`ed, however, only the # specified ones are. Since `RAILS_ENV` is common, we pass it. # env = env.merge(rails_env: fetch(:rails_env)) SSHKit::Command.new(*args, options.merge( { in: pwd_path, env: env, host: @host, user: user, group: @group, } )) end
execute_command(cmd)
click to toggle source
# File lib/sshkit/sudo/sudo_netssh.rb, line 98 def execute_command(cmd) output.log_command_start(cmd) cmd.started = true exit_status = nil with_ssh do |ssh| ssh.open_channel do |chan| chan.request_pty prepared_command = cmd.to_command if self.class.config.commands_log IO.write(self.class.config.commands_log, prepared_command + "\n", mode: 'a') end chan.exec prepared_command do |_ch, _success| chan.on_data do |ch, data| cmd.on_stdout(ch, data) skip_stdout_logging = SKIP_STDOUT_LOGGING_PATTERNS.any? { |pattern| data =~ pattern } output.log_command_data(cmd, :stdout, data) unless skip_stdout_logging end chan.on_extended_data do |ch, _type, data| cmd.on_stderr(ch, data) output.log_command_data(cmd, :stderr, data) end chan.on_request("exit-status") do |_ch, data| exit_status = data.read_long end #chan.on_request("exit-signal") do |ch, data| # # TODO: This gets called if the program is killed by a signal # # might also be a worthwhile thing to report # exit_signal = data.read_string.to_i # warn ">>> " + exit_signal.inspect # output.log_command_killed(cmd, exit_signal) #end chan.on_open_failed do |_ch| # TODO: What do do here? # I think we should raise something end chan.on_process do |_ch| # TODO: I don't know if this is useful end chan.on_eof do |_ch| # TODO: chan sends EOF before the exit status has been # writtend end end chan.wait end ssh.loop end # Set exit_status and log the result upon completion if exit_status cmd.exit_status = exit_status output.log_command_exit(cmd) end end