Module: Aptible::CLI::Helpers::Ssh
- Includes:
- ConfigPath
- Defined in:
- lib/aptible/cli/helpers/ssh.rb
Instance Method Summary collapse
- #connect_to_ssh_portal(operation, *extra_ssh_args) ⇒ Object
- #exit_with_ssh_portal(*args) ⇒ Object
- #with_ssh_cmd(operation) ⇒ Object
Methods included from ConfigPath
Instance Method Details
#connect_to_ssh_portal(operation, *extra_ssh_args) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/aptible/cli/helpers/ssh.rb', line 9 def connect_to_ssh_portal(operation, *extra_ssh_args) # NOTE: This is a little tricky to get rigt, so before you make any # changes, read this. # # - The first gotcha is that we cannot use Kernel.exec here, because # we need to perform cleanup when exiting from # operation#with_ssh_cmd. # # - The second gotcha is that we need to somehow capture the exit # status, so that CLI commands that call the SSH portal can proxy # this back to their own caller (the most important one here is # aptible ssh). # # To do this, we have to handle interrutps as a signal, as opposed to # handle an Interrupt exception. The reason for this has to do with # how Ruby's wait is implemented (this happens in process.c's # rb_waitpid). There are two main considerations here: # # - It automatically resumes when it receives EINTR, so our control # is pretty high-level here. # - It handles interrupts prior to setting $? (this appears to have # changed between Ruby 2.2 and 2.3, perhaps the newer implementation # behaves differently). # # Unfortunately, this means that if we receive SIGINT while in # Process::wait2, then we never get access to SSH's exitstatus: Ruby # throws a Interrupt so we don't have a return value, and it doesn't # set $?, so we can't read it back there. # # Of course, we can't just call Proces::wait2 again, because at this # point, we've reaped our child. # # To solve this, we add our own signal handler on SIGINT, which # simply proxies SIGINT to SSH if we happen to have a different # process group (which shouldn't be the case), just to be safe and # let users exit the CLI. with_ssh_cmd(operation) do |base_ssh_cmd| spawn_passthrough(base_ssh_cmd + extra_ssh_args) end end |
#exit_with_ssh_portal(*args) ⇒ Object
50 51 52 |
# File 'lib/aptible/cli/helpers/ssh.rb', line 50 def exit_with_ssh_portal(*args) exit connect_to_ssh_portal(*args) end |
#with_ssh_cmd(operation) ⇒ Object
54 55 56 57 58 59 60 61 62 |
# File 'lib/aptible/cli/helpers/ssh.rb', line 54 def with_ssh_cmd(operation) ensure_ssh_dir! ensure_config! ensure_key! operation.with_ssh_cmd(private_key_file) do |cmd, connection| yield cmd + common_ssh_args, connection end end |