Module: Net::SSH::Multi::SessionActions
- Included in:
- Session, Subsession
- Defined in:
- lib/net/ssh/multi/session_actions.rb
Overview
This module represents the actions that are available on session collections. Any class that includes this module needs only provide a servers
method that returns a list of Net::SSH::Multi::Server instances, and the rest just works. See Net::SSH::Multi::Session and Net::SSH::Multi::Subsession for consumers of this module.
Instance Method Summary collapse
-
#busy?(include_invisible = false) ⇒ Boolean
Returns
true
if any server in the current container has an open SSH session that is currently processing any channels. -
#connect! ⇒ Object
Connections are normally established lazily, as soon as they are needed.
-
#exec(command, &block) ⇒ Object
A convenience method for executing a command on multiple hosts and either displaying or capturing the output.
-
#master ⇒ Object
Returns the session that is the “master”.
-
#open_channel(type = "session", *extra, &on_confirm) ⇒ Object
Asks all sessions for all contained servers (see #sessions) to open a new channel.
-
#send_global_request(type, *extra, &callback) ⇒ Object
Sends a global request to the sessions for all contained servers (see #sessions).
-
#sessions ⇒ Object
Returns an array of all SSH sessions, blocking until all sessions have connected.
Instance Method Details
#busy?(include_invisible = false) ⇒ Boolean
Returns true
if any server in the current container has an open SSH session that is currently processing any channels. If include_invisible
is false
(the default) then invisible channels (such as those created by port forwarding) will not be counted; otherwise, they will be.
29 30 31 |
# File 'lib/net/ssh/multi/session_actions.rb', line 29 def busy?(include_invisible=false) servers.any? { |server| server.busy?(include_invisible) } end |
#connect! ⇒ Object
Connections are normally established lazily, as soon as they are needed. This method forces all servers in the current container to have their connections established immediately, blocking until the connections have been made.
20 21 22 23 |
# File 'lib/net/ssh/multi/session_actions.rb', line 20 def connect! sessions self end |
#exec(command, &block) ⇒ Object
A convenience method for executing a command on multiple hosts and either displaying or capturing the output. It opens a channel on all active sessions (see #open_channel and #active_sessions), and then executes a command on each channel (Net::SSH::Connection::Channel#exec).
If a block is given, it will be invoked whenever data is received across the channel, with three arguments: the channel object, a symbol identifying which output stream the data was received on (:stdout
or :stderr
) and a string containing the data that was received:
session.exec("command") do |ch, stream, data|
puts "[#{ch[:host]} : #{stream}] #{data}"
end
If no block is given, all output will be written to $stdout or $stderr, as appropriate.
Note that #exec will also capture the exit status of the process in the :exit_status
property of each channel. Since #exec returns all of the channels in a Net::SSH::Multi::Channel object, you can check for the exit status like this:
channel = session.exec("command") { ... }
channel.wait
if channel.any? { |c| c[:exit_status] != 0 }
puts "executing failed on at least one host!"
end
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/net/ssh/multi/session_actions.rb', line 119 def exec(command, &block) open_channel do |channel| channel.exec(command) do |ch, success| raise "could not execute command: #{command.inspect} (#{ch[:host]})" unless success channel.on_data do |ch, data| if block block.call(ch, :stdout, data) else data.chomp.each_line do |line| $stdout.puts("[#{ch[:host]}] #{line}") end end end channel.on_extended_data do |ch, type, data| if block block.call(ch, :stderr, data) else data.chomp.each_line do |line| $stderr.puts("[#{ch[:host]}] #{line}") end end end channel.on_request("exit-status") do |ch, data| ch[:exit_status] = data.read_long end end end end |
#master ⇒ Object
Returns the session that is the “master”. This defaults to self
, but classes that include this module may wish to change this if they are subsessions that depend on a master session.
12 13 14 |
# File 'lib/net/ssh/multi/session_actions.rb', line 12 def master self end |
#open_channel(type = "session", *extra, &on_confirm) ⇒ Object
Asks all sessions for all contained servers (see #sessions) to open a new channel. When each server responds, the on_confirm
block will be invoked with a single argument, the channel object for that server. This means that the block will be invoked one time for each session.
All new channels will be collected and returned, aggregated into a new Net::SSH::Multi::Channel instance.
Note that the channels are “enhanced” slightly–they have two properties set on them automatically, to make dealing with them in a multi-session environment slightly easier:
-
:server => the Net::SSH::Multi::Server instance that spawned the channel
-
:host => the host name of the server
Having access to these things lets you more easily report which host (e.g.) data was received from:
session.open_channel do |channel|
channel.exec "command" do |ch, success|
ch.on_data do |ch, data|
puts "got data #{data} from #{ch[:host]}"
end
end
end
80 81 82 83 84 85 86 87 88 89 |
# File 'lib/net/ssh/multi/session_actions.rb', line 80 def open_channel(type="session", *extra, &on_confirm) channels = sessions.map do |ssh| ssh.open_channel(type, *extra) do |c| c[:server] = c.connection[:server] c[:host] = c.connection[:server].host on_confirm[c] if on_confirm end end Multi::Channel.new(master, channels) end |
#send_global_request(type, *extra, &callback) ⇒ Object
Sends a global request to the sessions for all contained servers (see #sessions). This can be used to (e.g.) ping the remote servers to prevent them from timing out.
session.send_global_request("[email protected]")
If a block is given, it will be invoked when the server responds, with two arguments: the Net::SSH connection that is responding, and a boolean indicating whether the request succeeded or not.
50 51 52 53 |
# File 'lib/net/ssh/multi/session_actions.rb', line 50 def send_global_request(type, *extra, &callback) sessions.each { |ssh| ssh.send_global_request(type, *extra, &callback) } self end |
#sessions ⇒ Object
Returns an array of all SSH sessions, blocking until all sessions have connected.
35 36 37 38 39 |
# File 'lib/net/ssh/multi/session_actions.rb', line 35 def sessions threads = servers.map { |server| Thread.new { server.session(true) } if server.session.nil? } threads.each { |thread| thread.join if thread } servers.map { |server| server.session }.compact end |