From 73d75b2c3a5465392fd6210dbb844c49dd043cdc Mon Sep 17 00:00:00 2001 From: delano Date: Sun, 3 Apr 2011 16:39:47 -0400 Subject: Updated docs --- classes/Net/SSH.html | 87 +++++ classes/Net/SSH/Multi.html | 154 ++++++++ classes/Net/SSH/Multi/Channel.html | 537 +++++++++++++++++++++++++ classes/Net/SSH/Multi/ChannelProxy.html | 166 ++++++++ classes/Net/SSH/Multi/DynamicServer.html | 241 ++++++++++++ classes/Net/SSH/Multi/PendingConnection.html | 306 +++++++++++++++ classes/Net/SSH/Multi/Server.html | 438 +++++++++++++++++++++ classes/Net/SSH/Multi/ServerList.html | 224 +++++++++++ classes/Net/SSH/Multi/Session.html | 560 +++++++++++++++++++++++++++ classes/Net/SSH/Multi/SessionActions.html | 272 +++++++++++++ classes/Net/SSH/Multi/Subsession.html | 169 ++++++++ classes/Net/SSH/Multi/Version.html | 117 ++++++ 12 files changed, 3271 insertions(+) create mode 100644 classes/Net/SSH.html create mode 100644 classes/Net/SSH/Multi.html create mode 100644 classes/Net/SSH/Multi/Channel.html create mode 100644 classes/Net/SSH/Multi/ChannelProxy.html create mode 100644 classes/Net/SSH/Multi/DynamicServer.html create mode 100644 classes/Net/SSH/Multi/PendingConnection.html create mode 100644 classes/Net/SSH/Multi/Server.html create mode 100644 classes/Net/SSH/Multi/ServerList.html create mode 100644 classes/Net/SSH/Multi/Session.html create mode 100644 classes/Net/SSH/Multi/SessionActions.html create mode 100644 classes/Net/SSH/Multi/Subsession.html create mode 100644 classes/Net/SSH/Multi/Version.html (limited to 'classes/Net') diff --git a/classes/Net/SSH.html b/classes/Net/SSH.html new file mode 100644 index 0000000..241010c --- /dev/null +++ b/classes/Net/SSH.html @@ -0,0 +1,87 @@ + + + + : Net::SSH [Control multiple Net::SSH connections via a single interface.] + + + + + +
+ +
+
+
+
+

Classes and Modules

+ Module Net::SSH::Multi
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi.html b/classes/Net/SSH/Multi.html new file mode 100644 index 0000000..2fd28f8 --- /dev/null +++ b/classes/Net/SSH/Multi.html @@ -0,0 +1,154 @@ + + + + : Net::SSH::Multi [Control multiple Net::SSH connections via a single interface.] + + + + + +
+ +
+
+
+

+ Net::SSH::Multi is a library for controlling + multiple Net::SSH connections via a single + interface. It exposes an API similar to that of + Net::SSH::Connection::Session and Net::SSH::Connection::Channel, making it + simpler to adapt programs designed for single connections to be used with + multiple connections. +

+

+ This library is particularly useful for automating repetitive tasks that + must be performed on multiple machines. It executes the commands in + parallel, and allows commands to be executed on subsets of servers (defined + by groups). +

+
require 'net/ssh/multi'

Net::SSH::Multi.start do |session|
  # access servers via a gateway
  session.via 'gateway', 'gateway-user'

  # define the servers we want to use
  session.use 'user1@host1'
  session.use 'user2@host2'

  # define servers in groups for more granular access
  session.group :app do
    session.use 'user@app1'
    session.use 'user@app2'
  end

  # execute commands on all servers
  session.exec "uptime"

  # execute commands on a subset of servers
  session.with(:app).exec "hostname"

  # run the aggregated event loop
  session.loop
end
+

+ See Net::SSH::Multi::Session for more + documentation. +

+
+
+

Methods

+

public class

+
    +
  1. start
  2. +
+
+
+ +
+

Public class methods

+
+ +
+ start + (options={}) {|session| ...} +
+
+

+ This is a convenience method for instantiating a new Net::SSH::Multi::Session. If a block is + given, the session will be yielded to the block automatically closed (see + Net::SSH::Multi::Session#close) + when the block finishes. Otherwise, the new session will be returned. +

+
Net::SSH::Multi.start do |session|
  # ...
end

session = Net::SSH::Multi.start
# ...
session.close
+

+ Any options are passed directly to Net::SSH::Multi::Session.new (q.v.). +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi.rb, line 57
57:     def self.start(options={})
58:       session = Session.new(options)
59: 
60:       if block_given?
61:         begin
62:           yield session
63:           session.loop
64:           session.close
65:         end
66:       else
67:         return session
68:       end
69:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/Channel.html b/classes/Net/SSH/Multi/Channel.html new file mode 100644 index 0000000..779b48c --- /dev/null +++ b/classes/Net/SSH/Multi/Channel.html @@ -0,0 +1,537 @@ + + + + : Net::SSH::Multi::Channel [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::Channel +

+
    +
  1. + lib/net/ssh/multi/channel.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ Net::SSH::Multi::Channel encapsulates a + collection of Net::SSH::Connection::Channel instances from multiple + different connections. It allows for operations to be performed on all + contained channels, simultaneously, using an interface mostly identical to + Net::SSH::Connection::Channel itself. +

+

+ You typically obtain a Net::SSH::Multi::Channel + instance via Net::SSH::Multi::Session#open_channel or + Net::SSH::Multi::Session#exec, though there is nothing stopping you from + instantiating one yourself with a handful of Net::SSH::Connection::Channel + objects (though they should be associated with connections managed by a Net::SSH::Multi::Session object for consistent + behavior). +

+
channel = session.open_channel do |ch|
  # ...
end

channel.wait
+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. []
  2. +
  3. []=
  4. +
  5. active?
  6. +
  7. close
  8. +
  9. each
  10. +
  11. eof!
  12. +
  13. exec
  14. +
  15. on_close
  16. +
  17. on_data
  18. +
  19. on_eof
  20. +
  21. on_extended_data
  22. +
  23. on_open_failed
  24. +
  25. on_process
  26. +
  27. on_request
  28. +
  29. request_pty
  30. +
  31. send_data
  32. +
  33. wait
  34. +
+
+
+
+

Included modules

+
    +
  1. Enumerable
  2. +
+
+
+
+
+

Attributes

+
+ + + + + + + + + + + + + + + + +
channels[R] + + The collection of Net::SSH::Connection::Channel instances that this + multi-channel aggregates. +
connection[R] + + The Net::SSH::Multi::Session instance that + controls this channel collection. +
properties[R] + + A Hash of custom properties that may be set and queried on this object. +
+
+
+
+

Public class methods

+
+ +
+ new + (connection, channels) +
+
+

+ Instantiate a new Net::SSH::Multi::Channel + instance, controlled by the given connection (a Net::SSH::Multi::Session object) and wrapping the + given channels (Net::SSH::Connection::Channel instances). +

+

+ You will typically never call this directly; rather, you’ll get your + multi-channel references via Net::SSH::Multi::Session#open_channel and + friends. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel.rb, line 38
38:     def initialize(connection, channels)
39:       @connection = connection
40:       @channels = channels
41:       @properties = {}
42:     end
+
+
+

Public instance methods

+
+ +
+ [] + (key) +
+
+

+ Retrieve the property (see properties) with the given key. +

+
host = channel[:host]
+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel.rb, line 53
53:     def [](key)
54:       @properties[key]
55:     end
+
+
+
+ +
+ []= + (key, value) +
+
+

+ Set the property (see properties) with the given key to the given + value. +

+
channel[:visited] = true
+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel.rb, line 61
61:     def []=(key, value)
62:       @properties[key] = value
63:     end
+
+
+
+ +
+ active? + () +
+
+

+ Returns true as long as any of the component channels are active. +

+
connection.loop { channel.active? }
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 112
112:     def active?
113:       channels.any? { |channel| channel.active? }
114:     end
+
+
+
+ +
+ close + () +
+
+

+ Closes all component channels. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 127
127:     def close
128:       channels.each { |channel| channel.close }
129:       self
130:     end
+
+
+
+ +
+ each + () {|channel| ...} +
+
+

+ Iterate over each component channel object, yielding each in order to the + associated block. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel.rb, line 46
46:     def each
47:       @channels.each { |channel| yield channel }
48:     end
+
+
+
+ +
+ eof! + () +
+
+

+ Tells the remote process for each component channel not to expect any + further data from this end of the channel. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 134
134:     def eof!
135:       channels.each { |channel| channel.eof! }
136:       self
137:     end
+
+
+
+ +
+ exec + (command, &block) +
+
+

+ Perform an exec command on all component channels. The block, if + given, is passed to each component channel, so it will (potentially) be + invoked once for every channel in the collection. The block will receive + two parameters: the specific channel object being operated on, and a + boolean indicating whether the exec succeeded or not. +

+
channel.exec "ls -l" do |ch, success|
  # ...
end
+

+ See the documentation in Net::SSH for + Net::SSH::Connection::Channel#exec for more information on how to work with + the callback. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel.rb, line 77
77:     def exec(command, &block)
78:       channels.each { |channel| channel.exec(command, &block) }
79:       self
80:     end
+
+
+
+ +
+ on_close + (&block) +
+
+

+ Registers a callback on all component channels, to be invoked when the + remote server terminates the channel. The callback will be invoked with one + argument: the specific channel object being closed. +

+
channel.on_close do |ch|
  # ...
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 185
185:     def on_close(&block)
186:       channels.each { |channel| channel.on_close(&block) }
187:       self
188:     end
+
+
+
+ +
+ on_data + (&block) +
+
+

+ Registers a callback on all component channels, to be invoked when the + remote process emits data (usually on its stdout stream). The + block will be invoked with two arguments: the specific channel object, and + the data that was received. +

+
channel.on_data do |ch, data|
  puts "got data: #{data}"
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 147
147:     def on_data(&block)
148:       channels.each { |channel| channel.on_data(&block) }
149:       self
150:     end
+
+
+
+ +
+ on_eof + (&block) +
+
+

+ Registers a callback on all component channels, to be invoked when the + remote server has no further data to send. The callback will be invoked + with one argument: the specific channel object being marked EOF. +

+
channel.on_eof do |ch|
  # ...
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 197
197:     def on_eof(&block)
198:       channels.each { |channel| channel.on_eof(&block) }
199:       self
200:     end
+
+
+
+ +
+ on_extended_data + (&block) +
+
+

+ Registers a callback on all component channels, to be invoked when the + remote process emits “extended” data (typically on its + stderr stream). The block will be invoked with three arguments: + the specific channel object, an integer describing the data type (usually a + 1 for stderr) and the data that was received. +

+
channel.on_extended_data do |ch, type, data|
  puts "got extended data: #{data}"
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 161
161:     def on_extended_data(&block)
162:       channels.each { |channel| channel.on_extended_data(&block) }
163:       self
164:     end
+
+
+
+ +
+ on_open_failed + (&block) +
+
+

+ Registers a callback on all component channels, to be invoked when the + remote server is unable to open the channel. The callback will be invoked + with three arguments: the channel object that couldn’t be opened, a + description of the error (as a string), and an integer code representing + the error. +

+
channel.on_open_failed do |ch, description, code|
  # ...
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 211
211:     def on_open_failed(&block)
212:       channels.each { |channel| channel.on_open_failed(&block) }
213:       self
214:     end
+
+
+
+ +
+ on_process + (&block) +
+
+

+ Registers a callback on all component channels, to be invoked during the + idle portion of the connection event loop. The callback will be invoked + with one argument: the specific channel object being processed. +

+
channel.on_process do |ch|
  # ...
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 173
173:     def on_process(&block)
174:       channels.each { |channel| channel.on_process(&block) }
175:       self
176:     end
+
+
+
+ +
+ on_request + (type, &block) +
+
+

+ Registers a callback on all component channels, to be invoked when the + remote server sends a channel request of the given type. The + callback will be invoked with two arguments: the specific channel object + receiving the request, and a Net::SSH::Buffer instance containing the + request-specific data. +

+
channel.on_request("exit-status") do |ch, data|
  puts "exited with #{data.read_long}"
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 225
225:     def on_request(type, &block)
226:       channels.each { |channel| channel.on_request(type, &block) }
227:       self
228:     end
+
+
+
+ +
+ request_pty + (opts={}, &block) +
+
+

+ Perform a request_pty command + on all component channels. The block, if given, is passed to each component + channel, so it will (potentially) be invoked once for every channel in the + collection. The block will receive two parameters: the specific channel + object being operated on, and a boolean indicating whether the pty request + succeeded or not. +

+
channel.request_pty do |ch, success|
  # ...
end
+

+ See the documentation in Net::SSH for + Net::SSH::Connection::Channel#request_pty for more information on how to + work with the callback. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel.rb, line 95
95:     def request_pty(opts={}, &block)
96:       channels.each { |channel| channel.request_pty(opts, &block) }
97:       self
98:     end
+
+
+
+ +
+ send_data + (data) +
+
+

+ Send the given data to each component channel. It will be sent to + the remote process, typically being received on the process’ + stdin stream. +

+
channel.send_data "password\n"
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 104
104:     def send_data(data)
105:       channels.each { |channel| channel.send_data(data) }
106:       self
107:     end
+
+
+
+ +
+ wait + () +
+
+

+ Runs the connection’s event loop until the channel is no longer + active (see active?). +

+
channel.exec "something"
channel.wait
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/channel.rb, line 121
121:     def wait
122:       connection.loop { active? }
123:       self
124:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/ChannelProxy.html b/classes/Net/SSH/Multi/ChannelProxy.html new file mode 100644 index 0000000..7a529c3 --- /dev/null +++ b/classes/Net/SSH/Multi/ChannelProxy.html @@ -0,0 +1,166 @@ + + + + : Net::SSH::Multi::ChannelProxy [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::ChannelProxy +

+
    +
  1. + lib/net/ssh/multi/channel_proxy.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ The ChannelProxy is a delegate class that + represents a channel that has not yet been opened. It is only used when Net::SSH::Multi is running with with a concurrent + connections limit (see Net::SSH::Multi::Session#concurrent_connections). +

+

+ You’ll never need to instantiate one of these directly, and will + probably (if all goes well!) never even notice when one of these is in use. + Essentially, it is spawned by a Net::SSH::Multi::PendingConnection when + the pending connection is asked to open a channel. Any actions performed on + the channel proxy will then be recorded, until a real channel is set as the + delegate (see delegate_to). At that + point, all recorded actions will be replayed on the channel, and any + subsequent actions will be immediately delegated to the channel. +

+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. delegate_to
  2. +
  3. method_missing
  4. +
+
+
+
+

Attributes

+
+ + + + + + +
on_confirm[R] + + This is the “on confirm” callback that gets called when the + real channel is opened. +
+
+
+
+

Public class methods

+
+ +
+ new + (&on_confirm) +
+
+

+ Instantiates a new channel proxy with the given on_confirm + callback. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel_proxy.rb, line 21
21:     def initialize(&on_confirm)
22:       @on_confirm = on_confirm
23:       @recordings = []
24:       @channel = nil
25:     end
+
+
+

Public instance methods

+
+ +
+ delegate_to + (channel) +
+
+

+ Instructs the proxy to delegate all further actions to the given + channel (which must be an instance of + Net::SSH::Connection::Channel). All recorded actions are immediately + replayed, in order, against the delegate channel. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel_proxy.rb, line 30
30:     def delegate_to(channel)
31:       @channel = channel
32:       @recordings.each do |sym, args, block|
33:         @channel.__send__(sym, *args, &block)
34:       end
35:     end
+
+
+
+ +
+ method_missing + (sym, *args, &block) +
+
+

+ If a channel delegate has been specified (see delegate_to), the method will be + immediately sent to the delegate. Otherwise, the call is added to the list + of recorded method calls, to be played back when a delegate is specified. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/channel_proxy.rb, line 41
41:     def method_missing(sym, *args, &block)
42:       if @channel
43:         @channel.__send__(sym, *args, &block)
44:       else
45:         @recordings << [sym, args, block]
46:       end
47:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/DynamicServer.html b/classes/Net/SSH/Multi/DynamicServer.html new file mode 100644 index 0000000..2829095 --- /dev/null +++ b/classes/Net/SSH/Multi/DynamicServer.html @@ -0,0 +1,241 @@ + + + + : Net::SSH::Multi::DynamicServer [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::DynamicServer +

+
    +
  1. + lib/net/ssh/multi/dynamic_server.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ Represents a lazily evaluated collection of servers. This will usually be + created via Net::SSH::Multi::Session#use(&block), + and is useful for creating server definitions where the name or address of + the servers are not known until run-time. +

+
session.use { lookup_ip_address_of_server }
+

+ This prevents lookup_ip_address_of_server from being invoked + unless the server is actually needed, at which point it is invoked and the + result cached. +

+

+ The callback should return either nil (in which case no new + servers are instantiated), a String (representing a connection + specification), an array of Strings, or an array of Net::SSH::Multi::Server instances. +

+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. []
  2. +
  3. []=
  4. +
  5. each
  6. +
  7. evaluate!
  8. +
  9. to_ary
  10. +
+
+
+
+

Attributes

+
+ + + + + + + + + + + + + + + + +
callback[R] + + The Proc object to call to evaluate the server(s) +
master[R] + + The Net::SSH::Multi::Session instance that owns + this dynamic server record. +
options[R] + + The hash of options that will be used to initialize the server records. +
+
+
+
+

Public class methods

+
+ +
+ new + (master, options, callback) +
+
+

+ Create a new DynamicServer record, owned + by the given Net::SSH::Multi::Session + master, with the given hash of options, and using the + given Proc callback to lazily evaluate the actual server + instances. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/dynamic_server.rb, line 32
32:     def initialize(master, options, callback)
33:       @master, @options, @callback = master, options, callback
34:       @servers = nil
35:     end
+
+
+

Public instance methods

+
+ +
+ [] + (key) +
+
+

+ Returns the value for the given key in the :properties hash of the + options. If no :properties hash exists in options, this + returns nil. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/dynamic_server.rb, line 39
39:     def [](key)
40:       (options[:properties] ||= {})[key]
41:     end
+
+
+
+ +
+ []= + (key, value) +
+
+

+ Sets the given key/value pair in the :properties key in the + options hash. If the options hash has no :properties key, it will be + created. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/dynamic_server.rb, line 45
45:     def []=(key, value)
46:       (options[:properties] ||= {})[key] = value
47:     end
+
+
+
+ +
+ each + () {|server| ...} +
+
+

+ Iterates over every instantiated server record in this dynamic server. If + the servers have not yet been instantiated, this does nothing (e.g., it + does not automatically invoke evaluate!). +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/dynamic_server.rb, line 52
52:     def each
53:       (@servers || []).each { |server| yield server }
54:     end
+
+
+
+ +
+ evaluate! + () +
+
+

+ Evaluates the callback and instantiates the servers, memoizing the result. + Subsequent calls to evaluate! will + simply return the cached list of servers. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/dynamic_server.rb, line 59
59:     def evaluate!
60:       @servers ||= Array(callback[options]).map do |server|
61:           case server
62:           when String then Net::SSH::Multi::Server.new(master, server, options)
63:           else server
64:           end
65:         end
66:     end
+
+
+
+ +
+ to_ary + () +
+
+

+ Alias for evaluate! +

+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/PendingConnection.html b/classes/Net/SSH/Multi/PendingConnection.html new file mode 100644 index 0000000..9c59193 --- /dev/null +++ b/classes/Net/SSH/Multi/PendingConnection.html @@ -0,0 +1,306 @@ + + + + : Net::SSH::Multi::PendingConnection [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::PendingConnection +

+
    +
  1. + lib/net/ssh/multi/pending_connection.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ A PendingConnection instance mimics a + Net::SSH::Connection::Session instance, without actually being an open + connection to a server. It is used by Net::SSH::Multi::Session when a concurrent + connection limit is in effect, so that a server can hang on to a + “connection” that isn’t really a connection. +

+

+ Any requests against this connection (like open_channel or send_global_request) are not + actually sent, but are added to a list of recordings. When the real session + is opened and replaces this pending connection, all recorded actions will + be replayed against that session. +

+

+ You’ll never need to initialize one of these directly, and (if all + goes well!) should never even notice that one of these is in use. Net::SSH::Multi::Session will instantiate these as + needed, and only when there is a concurrent connection limit. +

+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. busy?
  2. +
  3. channels
  4. +
  5. close
  6. +
  7. listeners
  8. +
  9. open_channel
  10. +
  11. postprocess
  12. +
  13. preprocess
  14. +
  15. replace_with
  16. +
  17. send_global_request
  18. +
+
+
+
+

Attributes

+
+ + + + + + +
server[R] + + The Net::SSH::Multi::Server object that + “owns” this pending connection. +
+
+
+
+

Public class methods

+
+ +
+ new + (server) +
+
+

+ Instantiates a new pending connection for the given Net::SSH::Multi::Server object. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 52
52:     def initialize(server)
53:       @server = server
54:       @recordings = []
55:     end
+
+
+

Public instance methods

+
+ +
+ busy? + (include_invisible=false) +
+
+

+ Always returns true, so that the pending connection looks active + until it can be truly opened and replaced with a real connection. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 82
82:     def busy?(include_invisible=false)
83:       true
84:     end
+
+
+
+ +
+ channels + () +
+
+

+ Returns an empty array, since a pending connection cannot have any real + channels. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 92
92:     def channels
93:       []
94:     end
+
+
+
+ +
+ close + () +
+
+

+ Does nothing, except to make a pending connection quack like a real + connection. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 87
87:     def close
88:       self
89:     end
+
+
+
+ +
+ listeners + () +
+
+

+ Returns an empty hash, since a pending connection has no real listeners. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/pending_connection.rb, line 107
107:     def listeners
108:       {}
109:     end
+
+
+
+ +
+ open_channel + (type="session", *extras, &on_confirm) +
+
+

+ Records that a channel open request has been made, and returns a new Net::SSH::Multi::ChannelProxy object to + represent the (as yet unopened) channel. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 67
67:     def open_channel(type="session", *extras, &on_confirm)
68:       channel = ChannelProxy.new(&on_confirm)
69:       @recordings << ChannelOpenRecording.new(type, extras, channel)
70:       return channel
71:     end
+
+
+
+ +
+ postprocess + (readers, writers) +
+
+

+ Returns true, and does nothing else. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/pending_connection.rb, line 102
102:     def postprocess(readers, writers)
103:       true
104:     end
+
+
+
+ +
+ preprocess + () +
+
+

+ Returns true, and does nothing else. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 97
97:     def preprocess
98:       true
99:     end
+
+
+
+ +
+ replace_with + (session) +
+
+

+ Instructs the pending session to replay all of its recordings against the + given session, and to then replace itself with the given session. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 59
59:     def replace_with(session)
60:       @recordings.each { |recording| recording.replay_on(session) }
61:       @server.replace_session(session)
62:     end
+
+
+
+ +
+ send_global_request + (type, *extra, &callback) +
+
+

+ Records that a global request has been made. The request is not actually + sent, and won’t be until replace_with is called. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/pending_connection.rb, line 75
75:     def send_global_request(type, *extra, &callback)
76:       @recordings << SendGlobalRequestRecording.new(type, extra, callback)
77:       self
78:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/Server.html b/classes/Net/SSH/Multi/Server.html new file mode 100644 index 0000000..17be26b --- /dev/null +++ b/classes/Net/SSH/Multi/Server.html @@ -0,0 +1,438 @@ + + + + : Net::SSH::Multi::Server [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::Server +

+
    +
  1. + lib/net/ssh/multi/server.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ Encapsulates the connection information for a single remote server, as well + as the Net::SSH session corresponding to that + information. You’ll rarely need to instantiate one of these directly: + instead, you should use Net::SSH::Multi::Session#use. +

+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. <=>
  2. +
  3. []
  4. +
  5. []=
  6. +
  7. busy?
  8. +
  9. close
  10. +
  11. fail!
  12. +
  13. failed?
  14. +
  15. hash
  16. +
  17. inspect
  18. +
  19. port
  20. +
  21. session
  22. +
  23. to_s
  24. +
+
+
+
+

Included modules

+
    +
  1. Comparable
  2. +
+
+
+
+
+

External Aliases

+
+ + + + + + +
==->eql?
+
+
+
+

Attributes

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
gateway[R] + + The Net::SSH::Gateway instance to use to establish the connection. Will be + nil if the connection should be established without a gateway. +
host[R] + + The host name (or IP address) of the server to connect to. +
master[R] + + The Net::SSH::Multi::Session instance that + manages this server instance. +
options[R] + + The Hash of additional options to pass to Net::SSH when connecting (including things like + :password, and so forth). +
user[R] + + The user name to use when logging into the server. +
+
+
+
+

Public class methods

+
+ +
+ new + (master, host, options={}) +
+
+

+ Creates a new Server instance with the given + connection information. The master argument must be a reference to + the Net::SSH::Multi::Session instance that will + manage this server reference. The options hash must conform to the + options described for Net::SSH::start, with two additions: +

+
    +
  • :via => a Net::SSH::Gateway instance to use when establishing a connection + to this server. + +
  • +
  • :user => the name of the user to use when logging into this server. + +
  • +
+

+ The host argument may include the username and port number, in + which case those values take precedence over similar values given in the + options: +

+
server = Net::SSH::Multi::Server.new(session, 'user@host:1234')
puts server.user #-> user
puts server.port #-> 1234
+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server.rb, line 43
43:     def initialize(master, host, options={})
44:       @master = master
45:       @options = options.dup
46: 
47:       @user, @host, port = host.match(/^(?:([^;,:=]+)@|)(.*?)(?::(\d+)|)$/)[1,3]
48: 
49:       user_opt, port_opt = @options.delete(:user), @options.delete(:port)
50: 
51:       @user = @user || user_opt || master.default_user
52:       port ||= port_opt
53: 
54:       @options[:port] = port.to_i if port
55: 
56:       @gateway = @options.delete(:via)
57:       @failed = false
58:     end
+
+
+

Public instance methods

+
+ +
+ <=> + (server) +
+
+

+ Gives server definitions a sort order, and allows comparison. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server.rb, line 79
79:     def <=>(server)
80:       [host, port, user] <=> [server.host, server.port, server.user]
81:     end
+
+
+
+ +
+ [] + (key) +
+
+

+ Returns the value of the server property with the given key. Server properties are described via the + :properties key in the options hash when defining the Server. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server.rb, line 63
63:     def [](key)
64:       (options[:properties] || {})[key]
65:     end
+
+
+
+ +
+ []= + (key, value) +
+
+

+ Sets the given key/value pair in the :properties key in the + options hash. If the options hash has no :properties key, it will be + created. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server.rb, line 69
69:     def []=(key, value)
70:       (options[:properties] ||= {})[key] = value
71:     end
+
+
+
+ +
+ busy? + (include_invisible=false) +
+
+

+ Returns true if the session has been opened, and the session is + currently busy (as defined by Net::SSH::Connection::Session#busy?). +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 143
143:     def busy?(include_invisible=false)
144:       session && session.busy?(include_invisible)
145:     end
+
+
+
+ +
+ close + () +
+
+

+ Closes this server’s session. If the session has not yet been opened, + this does nothing. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 149
149:     def close
150:       session.close if session
151:     ensure
152:       master.server_closed(self) if session
153:       @session = nil
154:     end
+
+
+
+ +
+ fail! + (flag=true) +
+
+

+ Indicates (by default) that this server has just failed a connection + attempt. If flag is false, this can be used to reset the failed + flag so that a retry may be attempted. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 115
115:     def fail!(flag=true)
116:       @failed = flag
117:     end
+
+
+
+ +
+ failed? + () +
+
+

+ Returns true if this server has ever failed a connection attempt. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 108
108:     def failed?
109:       @failed
110:     end
+
+
+
+ +
+ hash + () +
+
+

+ Generates a Fixnum hash value for this object. This function has + the property that +a.eql?(b)+ implies +a.hash == b.hash+. The hash value is + used by class Hash. Any hash value that exceeds the capacity of a + Fixnum will be truncated before being used. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server.rb, line 89
89:     def hash
90:       @hash ||= [host, user, port].hash
91:     end
+
+
+
+ +
+ inspect + () +
+
+

+ Returns a human-readable representation of this server instance. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 103
103:     def inspect
104:       @inspect ||= "#<%s:0x%x %s>" % [self.class.name, object_id, to_s]
105:     end
+
+
+
+ +
+ port + () +
+
+

+ Returns the port number to use for this connection. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server.rb, line 74
74:     def port
75:       options[:port] || 22
76:     end
+
+
+
+ +
+ session + (require_session=false) +
+
+

+ Returns the Net::SSH session object for this + server. If require_session is false and the session has not + previously been created, this will return nil. If + require_session is true, the session will be instantiated if it + has not already been instantiated, via the gateway if one is + given, or directly (via Net::SSH::start) otherwise. +

+
if server.session.nil?
  puts "connecting..."
  server.session(true)
end
+

+ Note that the sessions returned by this are “enhanced” + slightly, to make them easier to deal with in a multi-session environment: + they have a :server property automatically set on them, that refers to this + object (the Server instance that spawned them). +

+
assert_equal server, server.session[:server]
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 136
136:     def session(require_session=false)
137:       return @session if @session || !require_session
138:       @session ||= master.next_session(self)
139:     end
+
+
+
+ +
+ to_s + () +
+
+

+ Returns a human-readable representation of this server instance. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/server.rb, line 94
 94:     def to_s
 95:       @to_s ||= begin
 96:         s = "#{user}@#{host}"
 97:         s << ":#{options[:port]}" if options[:port]
 98:         s
 99:       end
100:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/ServerList.html b/classes/Net/SSH/Multi/ServerList.html new file mode 100644 index 0000000..5c29cac --- /dev/null +++ b/classes/Net/SSH/Multi/ServerList.html @@ -0,0 +1,224 @@ + + + + : Net::SSH::Multi::ServerList [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::ServerList +

+
    +
  1. + lib/net/ssh/multi/server_list.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ Encapsulates a list of server objects, both dynamic (Net::SSH::Multi::DynamicServer) and static + (Net::SSH::Multi::Server). It attempts to make it + transparent whether a dynamic server set has been evaluated or not. Note + that a ServerList is NOT an Array, though it + is Enumerable. +

+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. add
  2. +
  3. concat
  4. +
  5. each
  6. +
  7. flatten
  8. +
  9. select
  10. +
  11. to_ary
  12. +
+
+
+
+

Included modules

+
    +
  1. Enumerable
  2. +
+
+
+
+
+

Public class methods

+
+ +
+ new + (list=[]) +
+
+

+ Create a new ServerList that wraps the given + server list. Duplicate entries will be discarded. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server_list.rb, line 15
15:     def initialize(list=[])
16:       @list = list.uniq
17:     end
+
+
+

Public instance methods

+
+ +
+ add + (server) +
+
+

+ Adds the given server to the list, and returns the argument. If an + identical server definition already exists in the collection, the argument + is not added, and the existing server record is returned instead. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server_list.rb, line 23
23:     def add(server)
24:       index = @list.index(server)
25:       if index
26:         server = @list[index]
27:       else
28:         @list.push(server)
29:       end
30:       server
31:     end
+
+
+
+ +
+ concat + (servers) +
+
+

+ Adds an array (or otherwise Enumerable list) of servers to this list, by + calling add for each argument. + Returns self. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server_list.rb, line 35
35:     def concat(servers)
36:       servers.each { |server| add(server) }
37:       self
38:     end
+
+
+
+ +
+ each + () {|server| ...} +
+
+

+ Iterates over each distinct server record in the collection. This will + correctly iterate over server records instantiated by a DynamicServer as well, but only if the + dynamic server has been “evaluated” (see Net::SSH::Multi::DynamicServer#evaluate!). +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server_list.rb, line 44
44:     def each
45:       @list.each do |server|
46:         case server
47:         when Server then yield server
48:         when DynamicServer then server.each { |item| yield item }
49:         else raise ArgumentError, "server list contains non-server: #{server.class}"
50:         end
51:       end
52:       self
53:     end
+
+
+
+ +
+ flatten + () +
+
+

+ Returns an array of all servers in the list, with dynamic server records + expanded. The result is an array of distinct server records (duplicates are + removed from the result). +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server_list.rb, line 65
65:     def flatten
66:       result = @list.inject([]) do |aggregator, server|
67:         case server
68:         when Server then aggregator.push(server)
69:         when DynamicServer then aggregator.concat(server)
70:         else raise ArgumentError, "server list contains non-server: #{server.class}"
71:         end
72:       end
73: 
74:       result.uniq
75:     end
+
+
+
+ +
+ select + () {|i| ...} +
+
+

+ Works exactly as Enumerable#select, but returns the result as a new ServerList instance. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/server_list.rb, line 57
57:     def select
58:       subset = @list.select { |i| yield i }
59:       ServerList.new(subset)
60:     end
+
+
+
+ +
+ to_ary + () +
+
+

+ Alias for flatten +

+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/Session.html b/classes/Net/SSH/Multi/Session.html new file mode 100644 index 0000000..e0ba392 --- /dev/null +++ b/classes/Net/SSH/Multi/Session.html @@ -0,0 +1,560 @@ + + + + : Net::SSH::Multi::Session [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::Session +

+
    +
  1. + lib/net/ssh/multi/session.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ Represents a collection of connections to various servers. It provides an + interface for organizing the connections (group), as well as a way to scope commands + to a subset of all connections (with). + You can also provide a default gateway connection that servers should use + when connecting (via). It exposes an + interface similar to Net::SSH::Connection::Session for opening SSH channels and executing commands, allowing for + these operations to be done in parallel across multiple connections. +

+
Net::SSH::Multi.start do |session|
  # access servers via a gateway
  session.via 'gateway', 'gateway-user'

  # define the servers we want to use
  session.use 'user1@host1'
  session.use 'user2@host2'

  # define servers in groups for more granular access
  session.group :app do
    session.use 'user@app1'
    session.use 'user@app2'
  end

  # execute commands on all servers
  session.exec "uptime"

  # execute commands on a subset of servers
  session.with(:app).exec "hostname"

  # run the aggregated event loop
  session.loop
end
+

+ Note that connections are established lazily, as soon as they are needed. + You can force the connections to be opened immediately, though, using the + connect! method. +

+

Concurrent Connection Limiting

+

+ Sometimes you may be dealing with a large number of servers, and if you try + to have connections open to all of them simultaneously you’ll run + into open file handle limitations and such. If this happens to you, you can + set the concurrent_connections property of the session. Net::SSH::Multi will then ensure that no more than + this number of connections are ever open simultaneously. +

+
Net::SSH::Multi.start(:concurrent_connections => 5) do |session|
  # ...
end
+

+ Opening channels and executing commands will still work exactly as before, + but Net::SSH::Multi will transparently close + finished connections and open pending ones. +

+

Controlling Connection Errors

+

+ By default, Net::SSH::Multi will raise an + exception if a connection error occurs when connecting to a server. This + will typically bubble up and abort the entire connection process. + Sometimes, however, you might wish to ignore connection errors, for + instance when starting a daemon on a large number of boxes and you know + that some of the boxes are going to be unavailable. +

+

+ To do this, simply set the on_error property of the session to :ignore (or + to :warn, if you want a warning message when a connection attempt fails): +

+
Net::SSH::Multi.start(:on_error => :ignore) do |session|
  # ...
end
+

+ The default is :fail, which causes the exception to bubble up. + Additionally, you can specify a Proc object as the value for on_error, + which will be invoked with the server in question if the connection attempt + fails. You can force the connection attempt to retry by throwing the :go + symbol, with :retry as the payload, or force the exception to be reraised + by throwing :go with :raise as the payload: +

+
handler = Proc.new do |server|
  server[:connection_attempts] ||= 0
  if server[:connection_attempts] < 3
    server[:connection_attempts] += 1
    throw :go, :retry
  else
    throw :go, :raise
  end
end

Net::SSH::Multi.start(:on_error => handler) do |session|
  # ...
end
+

+ Any other thrown value (or no thrown value at all) will result in the + failure being ignored. +

+

Lazily Evaluated Server Definitions

+

+ Sometimes you might be dealing with an environment where you don’t + know the names or addresses of the servers until runtime. You can certainly + dynamically build server names and pass them to use, but if the operation to determine the + server names is expensive, you might want to defer it until the server is + actually needed (especially if the logic of your program is such that you + might not even need to connect to that server every time the program runs). +

+

+ You can do this by passing a block to use: +

+
session.use do |opt|
  lookup_ip_address_of_remote_host
end
+

+ See use for more information about this + usage. +

+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. close
  2. +
  3. group
  4. +
  5. loop
  6. +
  7. loop_forever
  8. +
  9. on
  10. +
  11. process
  12. +
  13. servers
  14. +
  15. servers_for
  16. +
  17. use
  18. +
  19. via
  20. +
  21. with
  22. +
+
+
+
+

Included modules

+
    +
  1. SessionActions
  2. +
+
+
+
+
+

Attributes

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
concurrent_connections[RW] + + The number of allowed concurrent connections. No more than this number of + sessions will be open at any given time. +
default_gateway[R] + + The default Net::SSH::Gateway instance to use to connect to the servers. If + nil, no default gateway will be used. +
default_user[RW] + + The default user name to use when connecting to a server. If a user name is + not given for a particular server, this value will be used. It defaults to + ENV[‘USER’] || ENV[‘USERNAME’], or + “unknown” if neither of those are set. +
groups[R] + + The hash of group definitions, mapping each group name to a corresponding + Net::SSH::Multi::ServerList. +
on_error[RW] + + How connection errors should be handled. This defaults to :fail, but may be + set to :ignore if connection errors should be ignored, or :warn if + connection errors should cause a warning. +
server_list[R] + + The Net::SSH::Multi::ServerList managed by + this session. +
+
+
+
+

Public class methods

+
+ +
+ new + (options={}) +
+
+

+ Creates a new Net::SSH::Multi::Session instance. + Initially, it contains no server definitions, no group definitions, and no + default gateway. +

+

+ You can set the concurrent_connections property in the options. Setting it + to nil (the default) will cause Net::SSH::Multi to ignore any concurrent + connection limit and allow all defined sessions to be open simultaneously. + Setting it to an integer will cause Net::SSH::Multi to allow no more than that number + of concurrently open sessions, opening subsequent sessions only when other + sessions finish and close. +

+
Net::SSH::Multi.start(:concurrent_connections => 10) do |session|
  session.use ...
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 171
171:     def initialize(options={})
172:       @server_list = ServerList.new
173:       @groups = Hash.new { |h,k| h[k] = ServerList.new }
174:       @gateway = nil
175:       @open_groups = []
176:       @connect_threads = []
177:       @on_error = :fail
178:       @default_user = ENV['USER'] || ENV['USERNAME'] || "unknown"
179: 
180:       @open_connections = 0
181:       @pending_sessions = []
182:       @session_mutex = Mutex.new
183: 
184:       options.each { |opt, value| send("#{opt}=", value) }
185:     end
+
+
+

Public instance methods

+
+ +
+ close + () +
+
+

+ Closes the multi-session by shutting down all open server sessions, and the + default gateway (if one was specified using via). Note that other gateway connections + (e.g., those passed to use directly) + will not be closed by this method, and must be managed externally. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 402
402:     def close
403:       server_list.each { |server| server.close_channels }
404:       loop(0) { busy?(true) }
405:       server_list.each { |server| server.close }
406:       default_gateway.shutdown! if default_gateway
407:     end
+
+
+
+ +
+ group + (*args) {|self| ...} +
+
+

+ At its simplest, this associates a named group with a server definition. It + can be used in either of two ways: +

+

+ First, you can use it to associate a group (or array of groups) with a + server definition (or array of server definitions). The server definitions + must already exist in the server_list array (typically by calling use): +

+
server1 = session.use('host1', 'user1')
server2 = session.use('host2', 'user2')
session.group :app => server1, :web => server2
session.group :staging => [server1, server2]
session.group %w(xen linux) => server2
session.group %w(rackspace backup) => [server1, server2]
+

+ Secondly, instead of a mapping of groups to servers, you can just provide a + list of group names, and then a block. Inside the block, any calls to use will automatically associate the new + server definition with those groups. You can nest group calls, too, which will aggregate the + group definitions. +

+
session.group :rackspace, :backup do
  session.use 'host1', 'user1'
  session.group :xen do
    session.use 'host2', 'user2'
  end
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 213
213:     def group(*args)
214:       mapping = args.last.is_a?(Hash) ? args.pop : {}
215: 
216:       if mapping.any? && block_given?
217:         raise ArgumentError, "must provide group mapping OR block, not both"
218:       elsif block_given?
219:         begin
220:           saved_groups = open_groups.dup
221:           open_groups.concat(args.map { |a| a.to_sym }).uniq!
222:           yield self
223:         ensure
224:           open_groups.replace(saved_groups)
225:         end
226:       else
227:         mapping.each do |key, value|
228:           (open_groups + Array(key)).uniq.each do |grp|
229:             groups[grp.to_sym].concat(Array(value))
230:           end
231:         end
232:       end
233:     end
+
+
+
+ +
+ loop + (wait=nil, &block) +
+
+

+ Run the aggregated event loop for all open server sessions, until the given + block returns false. If no block is given, the loop will run for + as long as busy? returns true (in other words, for as long as + there are any (non-invisible) channels open). +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 415
415:     def loop(wait=nil, &block)
416:       running = block || Proc.new { |c| busy? }
417:       loop_forever { break unless process(wait, &running) }
418:     end
+
+
+
+ +
+ loop_forever + (wait=nil, &block) +
+
+

+ Alias for loop +

+
+
+
+ +
+ on + (*servers) {|subsession if block_given?| ...} +
+
+

+ Works as with, but for specific servers + rather than groups. It will return a new subsession (Net::SSH::Multi::Subsession) consisting of the + given servers. (Note that it requires that the servers in question have + been created via calls to use on this + session object, or things will not work quite right.) If a block is given, + the new subsession will also be yielded to the block. +

+
srv1 = session.use('host1', 'user')
srv2 = session.use('host2', 'user')
# ...
session.on(srv1, srv2).exec('hostname')
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 392
392:     def on(*servers)
393:       subsession = Subsession.new(self, servers)
394:       yield subsession if block_given?
395:       subsession
396:     end
+
+
+
+ +
+ process + (wait=nil, &block) +
+
+

+ Run a single iteration of the aggregated event loop for all open server + sessions. The wait parameter indicates how long to wait for an + event to appear on any of the different sessions; nil (the + default) means “wait forever”. If the block is given, then it + will be used to determine whether process returns true (the block + did not return false), or false (the block returned + false). +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 426
426:     def process(wait=nil, &block)
427:       realize_pending_connections!
428:       wait = @connect_threads.any? ? 0 : wait
429: 
430:       return false unless preprocess(&block)
431: 
432:       readers = server_list.map { |s| s.readers }.flatten
433:       writers = server_list.map { |s| s.writers }.flatten
434: 
435:       readers, writers, = IO.select(readers, writers, nil, wait)
436: 
437:       if readers
438:         return postprocess(readers, writers)
439:       else
440:         return true
441:       end
442:     end
+
+
+
+ +
+ servers + () +
+
+

+ Essentially an alias for servers_for + without any arguments. This is used primarily to satistfy the expectations + of the Net::SSH::Multi::SessionActions + module. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 293
293:     def servers
294:       servers_for
295:     end
+
+
+
+ +
+ servers_for + (*criteria) +
+
+

+ Returns the set of servers that match the given criteria. It can be used in + any (or all) of three ways. +

+

+ First, you can omit any arguments. In this case, the full list of servers + will be returned. +

+
all = session.servers_for
+

+ Second, you can simply specify a list of group names. All servers in all + named groups will be returned. If a server belongs to multiple matching + groups, then it will appear only once in the list (the resulting list will + contain only unique servers). +

+
servers = session.servers_for(:app, :db)
+

+ Last, you can specify a hash with group names as keys, and property + constraints as the values. These property constraints are either + “only” constraints (which restrict the set of servers to + “only” those that match the given properties) or + “except” constraints (which restrict the set of servers to + those whose properties do not match). Properties are described + when the server is defined (via the :properties key): +

+
session.group :db do
  session.use 'dbmain', 'user', :properties => { :primary => true }
  session.use 'dbslave', 'user2'
  session.use 'dbslve2', 'user2'
end

# return ONLY on the servers in the :db group which have the :primary
# property set to true.
primary = session.servers_for(:db => { :only => { :primary => true } })
+

+ You can, naturally, combine these methods: +

+
# all servers in :app and :web, and all servers in :db with the
# :primary property set to true
servers = session.servers_for(:app, :web, :db => { :only => { :primary => true } })
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 334
334:     def servers_for(*criteria)
335:       if criteria.empty?
336:         server_list.flatten
337:       else
338:         # normalize the criteria list, so that every entry is a key to a
339:         # criteria hash (possibly empty).
340:         criteria = criteria.inject({}) do |hash, entry|
341:           case entry
342:           when Hash then hash.merge(entry)
343:           else hash.merge(entry => {})
344:           end
345:         end
346: 
347:         list = criteria.inject([]) do |aggregator, (group, properties)|
348:           raise ArgumentError, "the value for any group must be a Hash, but got a #{properties.class} for #{group.inspect}" unless properties.is_a?(Hash)
349:           bad_keys = properties.keys - [:only, :except]
350:           raise ArgumentError, "unknown constraint(s) #{bad_keys.inspect} for #{group.inspect}" unless bad_keys.empty?
351: 
352:           servers = groups[group].select do |server|
353:             (properties[:only] || {}).all? { |prop, value| server[prop] == value } &&
354:             !(properties[:except] || {}).any? { |prop, value| server[prop] == value }
355:           end
356: 
357:           aggregator.concat(servers)
358:         end
359: 
360:         list.uniq
361:       end
362:     end
+
+
+
+ +
+ use + (*hosts, &block) +
+
+

+ Defines a new server definition, to be managed by this session. The server + is at the given host, and will be connected to as the given + user. The other options are passed as-is to the Net::SSH session constructor. +

+

+ If a default gateway has been specified previously (with via) it will be passed to the new server + definition. You can override this by passing a different Net::SSH::Gateway + instance (or nil) with the :via key in the options. +

+
session.use 'host'
session.use 'user@host2', :via => nil
session.use 'host3', :user => "user3", :via => Net::SSH::Gateway.new('gateway.host', 'user')
+

+ If only a single host is given, the new server instance is returned. You + can give multiple hosts at a time, though, in which case an array of server + instances will be returned. +

+
server1, server2 = session.use "host1", "host2"
+

+ If given a block, this will save the block as a Net::SSH::Multi::DynamicServer definition, to + be evaluated lazily the first time the server is needed. The block will + recive any options hash given to use, + and should return nil (if no servers are to be added), a String or + an array of Strings (to be interpreted as a connection specification), or a + Server or an array of Servers. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 274
274:     def use(*hosts, &block)
275:       options = hosts.last.is_a?(Hash) ? hosts.pop : {}
276:       options = { :via => default_gateway }.merge(options)
277: 
278:       results = hosts.map do |host|
279:         server_list.add(Server.new(self, host, options))
280:       end
281: 
282:       if block
283:         results << server_list.add(DynamicServer.new(self, options, block))
284:       end
285: 
286:       group [] => results
287:       results.length > 1 ? results : results.first
288:     end
+
+
+
+ +
+ via + (host, user, options={}) +
+
+

+ Sets up a default gateway to use when establishing connections to servers. + Note that any servers defined prior to this invocation will not use the + default gateway; it only affects servers defined subsequently. +

+
session.via 'gateway.host', 'user'
+

+ You may override the default gateway on a per-server basis by passing the + :via key to the use method; see use for details. +

+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 243
243:     def via(host, user, options={})
244:       @default_gateway = Net::SSH::Gateway.new(host, user, options)
245:       self
246:     end
+
+
+
+ +
+ with + (*groups) {|subsession if block_given?| ...} +
+
+

+ Returns a new Net::SSH::Multi::Subsession + instance consisting of the servers that meet the given criteria. If a block + is given, the subsession will be yielded to it. See servers_for for a discussion of how these + criteria are interpreted. +

+
session.with(:app).exec('hostname')

session.with(:app, :db => { :primary => true }) do |s|
  s.exec 'date'
  s.exec 'uptime'
end
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session.rb, line 375
375:     def with(*groups)
376:       subsession = Subsession.new(self, servers_for(*groups))
377:       yield subsession if block_given?
378:       subsession
379:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/SessionActions.html b/classes/Net/SSH/Multi/SessionActions.html new file mode 100644 index 0000000..ad9a7b4 --- /dev/null +++ b/classes/Net/SSH/Multi/SessionActions.html @@ -0,0 +1,272 @@ + + + + : Net::SSH::Multi::SessionActions [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Module + Net::SSH::Multi::SessionActions +

+
    +
  1. + lib/net/ssh/multi/session_actions.rb +
  2. +
+
+
+
+
+

+ 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. +

+
+
+

Methods

+

public instance

+
    +
  1. busy?
  2. +
  3. connect!
  4. +
  5. exec
  6. +
  7. master
  8. +
  9. open_channel
  10. +
  11. send_global_request
  12. +
  13. sessions
  14. +
+
+
+
+

Public instance methods

+
+ +
+ busy? + (include_invisible=false) +
+
+

+ 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. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/session_actions.rb, line 29
29:     def busy?(include_invisible=false)
30:       servers.any? { |server| server.busy?(include_invisible) }
31:     end
+
+
+
+ +
+ connect! + () +
+
+

+ 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. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/session_actions.rb, line 20
20:     def connect!
21:       sessions
22:       self
23:     end
+
+
+
+ +
+ exec + (command, &block) +
+
+

+ 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
+
+
+ + [show source] + +
     # File lib/net/ssh/multi/session_actions.rb, line 119
119:     def exec(command, &block)
120:       open_channel do |channel|
121:         channel.exec(command) do |ch, success|
122:           raise "could not execute command: #{command.inspect} (#{ch[:host]})" unless success
123: 
124:           channel.on_data do |ch, data|
125:             if block
126:               block.call(ch, :stdout, data)
127:             else
128:               data.chomp.each_line do |line|
129:                 $stdout.puts("[#{ch[:host]}] #{line}")
130:               end
131:             end
132:           end
133: 
134:           channel.on_extended_data do |ch, type, data|
135:             if block
136:               block.call(ch, :stderr, data)
137:             else
138:               data.chomp.each_line do |line|
139:                 $stderr.puts("[#{ch[:host]}] #{line}")
140:               end
141:             end
142:           end
143: 
144:           channel.on_request("exit-status") do |ch, data|
145:             ch[:exit_status] = data.read_long
146:           end
147:         end
148:       end
149:     end
+
+
+
+ +
+ master + () +
+
+

+ 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. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/session_actions.rb, line 12
12:     def master
13:       self
14:     end
+
+
+
+ +
+ open_channel + (type="session", *extra, &on_confirm) +
+
+

+ 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
+
+
+ + [show source] + +
    # File lib/net/ssh/multi/session_actions.rb, line 80
80:     def open_channel(type="session", *extra, &on_confirm)
81:       channels = sessions.map do |ssh|
82:         ssh.open_channel(type, *extra) do |c|
83:           c[:server] = c.connection[:server]
84:           c[:host] = c.connection[:server].host
85:           on_confirm[c] if on_confirm
86:         end
87:       end
88:       Multi::Channel.new(master, channels)
89:     end
+
+
+
+ +
+ send_global_request + (type, *extra, &callback) +
+
+

+ 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("keep-alive@openssh.com")
+

+ 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. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/session_actions.rb, line 50
50:     def send_global_request(type, *extra, &callback)
51:       sessions.each { |ssh| ssh.send_global_request(type, *extra, &callback) }
52:       self
53:     end
+
+
+
+ +
+ sessions + () +
+
+

+ Returns an array of all SSH sessions, blocking + until all sessions have connected. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/session_actions.rb, line 35
35:     def sessions
36:       threads = servers.map { |server| Thread.new { server.session(true) } if server.session.nil? }
37:       threads.each { |thread| thread.join if thread }
38:       servers.map { |server| server.session }.compact
39:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/Subsession.html b/classes/Net/SSH/Multi/Subsession.html new file mode 100644 index 0000000..e6268a7 --- /dev/null +++ b/classes/Net/SSH/Multi/Subsession.html @@ -0,0 +1,169 @@ + + + + : Net::SSH::Multi::Subsession [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::Subsession +

+
    +
  1. + lib/net/ssh/multi/subsession.rb +
  2. +
+
+ Parent: + Object +
+
+
+
+
+

+ A trivial class for representing a subset of servers. It is used internally + for restricting operations to a subset of all defined servers. +

+
subsession = session.with(:app)
subsession.exec("hostname")
+
+
+

Methods

+

public class

+
    +
  1. new
  2. +
+

public instance

+
    +
  1. first
  2. +
  3. slice
  4. +
+
+
+
+

Included modules

+
    +
  1. SessionActions
  2. +
+
+
+
+
+

Attributes

+
+ + + + + + + + + + + +
master[R] + + The master session that spawned this subsession. +
servers[R] + + The list of servers that this subsession can operate on. +
+
+
+
+

Public class methods

+
+ +
+ new + (master, server_list) +
+
+

+ Create a new subsession of the given master session, that operates + on the given server_list. +

+
+
+ + [show source] + +
    # File lib/net/ssh/multi/subsession.rb, line 22
22:     def initialize(master, server_list)
23:       @master  = master
24:       @servers = server_list.uniq
25:     end
+
+
+

Public instance methods

+
+ +
+ first + () +
+
+

+ Returns a new subsession that consists of only the first server in the + server list of the current subsession. This is just convenience for + slice(0): +

+
s1 = subsession.first
+
+
+ + [show source] + +
    # File lib/net/ssh/multi/subsession.rb, line 43
43:     def first
44:       slice(0)
45:     end
+
+
+
+ +
+ slice + (*args) +
+
+

+ Works as Array#slice, but returns a new subsession consisting of the given + slice of servers in this subsession. The new subsession will have the same + master session as this subsession does. +

+
s1 = subsession.slice(0)
s2 = subsession.slice(3, -1)
s3 = subsession.slice(1..4)
+
+
+ + [show source] + +
    # File lib/net/ssh/multi/subsession.rb, line 34
34:     def slice(*args)
35:       Subsession.new(master, Array(servers.slice(*args)))
36:     end
+
+
+
+
+
+
+ +
+ + + diff --git a/classes/Net/SSH/Multi/Version.html b/classes/Net/SSH/Multi/Version.html new file mode 100644 index 0000000..3b9b8ad --- /dev/null +++ b/classes/Net/SSH/Multi/Version.html @@ -0,0 +1,117 @@ + + + + : Net::SSH::Multi::Version [Control multiple Net::SSH connections via a single interface.] + + + + + +
+
+

+ Class + Net::SSH::Multi::Version +

+
    +
  1. + lib/net/ssh/multi/version.rb +
  2. +
+
+ Parent: + Net::SSH::Version +
+
+
+
+
+

+ A trivial class for representing the version of this library. +

+
+
+
+

Constants

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MAJOR=1  + + The major component of the library’s version +
MINOR=1  + + The minor component of the library’s version +
TINY=0  + + The tiny component of the library’s version +
CURRENT=new(MAJOR, MINOR, TINY)  + + The library’s version as a Version + instance +
STRING=CURRENT.to_s  + + The library’s version as a String instance +
+
+
+
+
+
+ +
+ + + -- cgit v1.2.1