Class: Aspera::Ssh
- Inherits:
-
Object
- Object
- Aspera::Ssh
- Defined in:
- lib/aspera/ssh.rb
Overview
A simple wrapper around Net::SSH executes one command and get its result from stdout
Defined Under Namespace
Classes: Error
Constant Summary collapse
- EXCLUDE_ECDSHA2 =
Regexp matching ecdsa/ecdh-sha2 algorithm names (JRuby workaround)
/^ecd(sa|h)-sha2/
Class Method Summary collapse
-
.disable_ecd_sha2_algorithms ⇒ void
Mutates Net::SSH internal algorithm lists to remove ecdsa/ecdh-sha2 entries globally.
-
.disable_ed25519_keys ⇒ void
Removes ed25519 keys from the default identity list used by Net::SSH.
-
.no_ecd_sha2_options ⇒ Hash{Symbol => Array<String>}
Returns Net::SSH option overrides that exclude all ecdsa/ecdh-sha2 algorithms.
Instance Method Summary collapse
-
#execute(cmd, input: nil) ⇒ String
Executes a single command on the remote host over a new SSH session.
-
#initialize(host, username, ssh_options) ⇒ Ssh
constructor
A new instance of Ssh.
Constructor Details
#initialize(host, username, ssh_options) ⇒ Ssh
Returns a new instance of Ssh.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/aspera/ssh.rb', line 61 def initialize(host, username, ) Aspera.assert_type(host, String) Aspera.assert_type(username, String) Aspera.assert_type(, Hash) Aspera.assert_hash_all(, Symbol, nil) @host = host @username = username @ssh_options = .dup @ssh_options[:logger] = Log.log unless @ssh_options.key?(:logger) @ssh_options[:verbose] = :warn unless @ssh_options.key?(:verbose) # @ssh_options[:verbose] = :debug @ssh_options[:use_agent] = false unless @ssh_options.key?(:use_agent) Log.log.debug { "ssh:#{@username}@#{@host}" } Log.dump(:ssh_options, @ssh_options) end |
Class Method Details
.disable_ecd_sha2_algorithms ⇒ void
This method returns an undefined value.
Mutates Net::SSH internal algorithm lists to remove ecdsa/ecdh-sha2 entries globally. Kept for backwards compatibility and JRuby usage; prefer no_ecd_sha2_options for new code.
50 51 52 53 54 |
# File 'lib/aspera/ssh.rb', line 50 def disable_ecd_sha2_algorithms Log.log.debug('Disabling SSH ecdsa (global)') Net::SSH::Transport::Algorithms::ALGORITHMS.each_value { |a| a.reject! { |a| a.match?(EXCLUDE_ECDSHA2) } } Net::SSH::KnownHosts::SUPPORTED_TYPE.reject! { |t| t.match?(EXCLUDE_ECDSHA2) } end |
.disable_ed25519_keys ⇒ void
This method returns an undefined value.
Removes ed25519 keys from the default identity list used by Net::SSH.
Called when the ed25519 gem is absent or explicitly disabled via
ASCLI_ENABLE_ED25519=false.
22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/aspera/ssh.rb', line 22 def disable_ed25519_keys Log.log.debug('Disabling SSH ed25519 user keys') old_verbose = $VERBOSE $VERBOSE = nil Net::SSH::Authentication::Session.class_eval do define_method(:default_keys) do %w[.ssh .ssh2].product(%w[rsa dsa ecdsa]).map { "~/#{_1}/id_#{_2}" }.freeze end private(:default_keys) end $VERBOSE = old_verbose end |
.no_ecd_sha2_options ⇒ Hash{Symbol => Array<String>}
Returns Net::SSH option overrides that exclude all ecdsa/ecdh-sha2 algorithms.
Merge the result into ssh_options passed to #initialize to avoid
mutating Net::SSH internal constants.
39 40 41 42 43 44 45 |
# File 'lib/aspera/ssh.rb', line 39 def Log.log.debug('Building SSH options without ecdsa/ecdh-sha2') { host_key: Net::SSH::Transport::Algorithms::ALGORITHMS[:host_key].reject { |a| a.match?(EXCLUDE_ECDSHA2) }, kex: Net::SSH::Transport::Algorithms::ALGORITHMS[:kex].reject { |a| a.match?(EXCLUDE_ECDSHA2) } } end |
Instance Method Details
#execute(cmd, input: nil) ⇒ String
Executes a single command on the remote host over a new SSH session.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/aspera/ssh.rb', line 82 def execute(cmd, input: nil) Aspera.assert_type(cmd, String) Log.log.debug { "cmd=#{cmd}" } # @type response [Array<String>] response = [] # @type error [Array<String>] error = [] exit_code = nil # @param session [Net::SSH::Connection::Session] Net::SSH.start(@host, @username, @ssh_options) do |session| # @param channel [Net::SSH::Connection::Channel] session.open_channel do |channel| # Register stdout/stderr before exec so no data is missed (e.g. ForceCommand errors) channel.on_data { |_ch, data| response.push(data) } channel.on_extended_data { |_ch, type, data| error.push(data) if type.eql?(1) } # @param data [Net::SSH::Buffer] channel.on_request('exit-status') do |_channel, data| Log.dump(:data, data, level: :trace1) exit_code = data.read_long end # send command to SSH channel (execute) cspell: disable-next-line channel.send('cexe'.reverse, cmd) do |_ch, success| raise Error, "could not execute command: #{cmd}" unless success channel.send_data(input) unless input.nil? end end # wait for channel to finish and flush the session session.loop end error_text = error.join hint = error_text.include?('Could not chdir to home directory') ? "\nHint: home not created in Windows?" : '' raise Error, "#{cmd}: exit #{exit_code}, #{error_text.chomp}#{hint}" if exit_code&.nonzero? Log.log.error { "#{error_text}#{hint}" } unless error_text.empty? # response as single string return response.join end |