diff options
Diffstat (limited to 'classes/Net/SSH/Multi/Session.html')
-rw-r--r-- | classes/Net/SSH/Multi/Session.html | 560 |
1 files changed, 560 insertions, 0 deletions
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 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html lang='en'> + <head> + <title>: Net::SSH::Multi::Session [Control multiple Net::SSH connections via a single interface.]</title> + <meta content='text/html; charset=utf-8' http-equiv='Content-Type'> + <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'> + <script type='text/javascript'> + //<![CDATA[ + function popupCode(url) { + window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400") + } + + function toggleCode(id) { + var code = document.getElementById(id) + + code.style.display = code.style.display != 'block' ? 'block' : 'none' + return true + } + + // Make codeblocks hidden by default + document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>') + //]]> + </script> + </head> + <body class='page'> + <div class='class' id='wrapper'> + <div class='header'> + <h1 class='name'> + <span class='type'>Class</span> + Net::SSH::Multi::Session + </h1> + <ol class='paths'> + <li> + <a href="../../../../files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a> + </li> + </ol> + <div class='parent'> + Parent: + <strong>Object</strong> + </div> + </div> + <div id='content'> + <div id='text'> + <div id='description'> + <p> + Represents a collection of connections to various servers. It provides an + interface for organizing the connections (<a + href="Session.html#M000067">group</a>), as well as a way to scope commands + to a subset of all connections (<a href="Session.html#M000072">with</a>). + You can also provide a default gateway connection that servers should use + when connecting (<a href="Session.html#M000068">via</a>). It exposes an + interface similar to Net::SSH::Connection::Session for opening <a + href="../../SSH.html">SSH</a> channels and executing commands, allowing for + these operations to be done in parallel across multiple connections. + </p> + <pre>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</pre> + <p> + 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. + </p> + <h2>Concurrent Connection Limiting</h2> + <p> + 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. <a + href="../Multi.html">Net::SSH::Multi</a> will then ensure that no more than + this number of connections are ever open simultaneously. + </p> + <pre>Net::SSH::Multi.start(:concurrent_connections => 5) do |session|
 # ...
end</pre> + <p> + Opening channels and executing commands will still work exactly as before, + but <a href="../Multi.html">Net::SSH::Multi</a> will transparently close + finished connections and open pending ones. + </p> + <h2>Controlling Connection Errors</h2> + <p> + By default, <a href="../Multi.html">Net::SSH::Multi</a> 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. + </p> + <p> + 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): + </p> + <pre>Net::SSH::Multi.start(:on_error => :ignore) do |session|
 # ...
end</pre> + <p> + 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: + </p> + <pre>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</pre> + <p> + Any other thrown value (or no thrown value at all) will result in the + failure being ignored. + </p> + <h2>Lazily Evaluated <a href="Server.html">Server</a> Definitions</h2> + <p> + 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 <a + href="Session.html#M000069">use</a>, 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). + </p> + <p> + You can do this by passing a block to <a + href="Session.html#M000069">use</a>: + </p> + <pre>session.use do |opt|
 lookup_ip_address_of_remote_host
end</pre> + <p> + See <a href="Session.html#M000069">use</a> for more information about this + usage. + </p> + </div> + <div id='method-list'> + <h2>Methods</h2> + <h3>public class</h3> + <ol> + <li><a href="#M000066">new</a></li> + </ol> + <h3>public instance</h3> + <ol> + <li><a href="#M000074">close</a></li> + <li><a href="#M000067">group</a></li> + <li><a href="#M000075">loop</a></li> + <li><a href="#M000076">loop_forever</a></li> + <li><a href="#M000073">on</a></li> + <li><a href="#M000077">process</a></li> + <li><a href="#M000070">servers</a></li> + <li><a href="#M000071">servers_for</a></li> + <li><a href="#M000069">use</a></li> + <li><a href="#M000068">via</a></li> + <li><a href="#M000072">with</a></li> + </ol> + </div> + <div id='context'> + <div id='includes'> + <h2>Included modules</h2> + <ol> + <li><a href="SessionActions.html">SessionActions</a></li> + </ol> + </div> + </div> + <div id='section'> + <div id='attribute-list'> + <h2 class='section-bar'>Attributes</h2> + <div class='name-list'> + <table> + <tr class='top-aligned-row context-row'> + <td class='context-item-name'>concurrent_connections</td> + <td class='context-item-value'>[RW]</td> + <td class='context-item-desc'> + + The number of allowed concurrent connections. No more than this number of + sessions will be open at any given time. + </td> + </tr> + <tr class='top-aligned-row context-row'> + <td class='context-item-name'>default_gateway</td> + <td class='context-item-value'>[R]</td> + <td class='context-item-desc'> + + The default Net::SSH::Gateway instance to use to connect to the servers. If + <tt>nil</tt>, no default gateway will be used. + </td> + </tr> + <tr class='top-aligned-row context-row'> + <td class='context-item-name'>default_user</td> + <td class='context-item-value'>[RW]</td> + <td class='context-item-desc'> + + 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. + </td> + </tr> + <tr class='top-aligned-row context-row'> + <td class='context-item-name'>groups</td> + <td class='context-item-value'>[R]</td> + <td class='context-item-desc'> + + The hash of group definitions, mapping each group name to a corresponding + <a href="ServerList.html">Net::SSH::Multi::ServerList</a>. + </td> + </tr> + <tr class='top-aligned-row context-row'> + <td class='context-item-name'>on_error</td> + <td class='context-item-value'>[RW]</td> + <td class='context-item-desc'> + + 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. + </td> + </tr> + <tr class='top-aligned-row context-row'> + <td class='context-item-name'>server_list</td> + <td class='context-item-value'>[R]</td> + <td class='context-item-desc'> + + The <a href="ServerList.html">Net::SSH::Multi::ServerList</a> managed by + this session. + </td> + </tr> + </table> + </div> + </div> + <div id='methods'> + <h2>Public class methods</h2> + <div class='method public-class' id='method-M000066'> + <a name='M000066'> </a> + <div class='synopsis'> + <span class='name'>new</span> + <span class='arguments'>(options={})</span> + </div> + <div class='description'> + <p> + Creates a new <a href="Session.html">Net::SSH::Multi::Session</a> instance. + Initially, it contains no server definitions, no group definitions, and no + default gateway. + </p> + <p> + You can set the concurrent_connections property in the options. Setting it + to <tt>nil</tt> (the default) will cause <a + href="../Multi.html">Net::SSH::Multi</a> to ignore any concurrent + connection limit and allow all defined sessions to be open simultaneously. + Setting it to an integer will cause <a + href="../Multi.html">Net::SSH::Multi</a> to allow no more than that number + of concurrently open sessions, opening subsequent sessions only when other + sessions finish and close. + </p> + <pre>Net::SSH::Multi.start(:concurrent_connections => 10) do |session|
 session.use ...
end</pre> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000066-source'); return false"> + [show source] + </a> + <pre id='M000066-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 171</span>
171: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">options</span>={})
172: <span class="ruby-ivar">@server_list</span> = <span class="ruby-constant">ServerList</span>.<span class="ruby-identifier">new</span>
173: <span class="ruby-ivar">@groups</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">h</span>,<span class="ruby-identifier">k</span><span class="ruby-operator">|</span> <span class="ruby-identifier">h</span>[<span class="ruby-identifier">k</span>] = <span class="ruby-constant">ServerList</span>.<span class="ruby-identifier">new</span> }
174: <span class="ruby-ivar">@gateway</span> = <span class="ruby-keyword kw">nil</span>
175: <span class="ruby-ivar">@open_groups</span> = []
176: <span class="ruby-ivar">@connect_threads</span> = []
177: <span class="ruby-ivar">@on_error</span> = <span class="ruby-identifier">:fail</span>
178: <span class="ruby-ivar">@default_user</span> = <span class="ruby-constant">ENV</span>[<span class="ruby-value str">'USER'</span>] <span class="ruby-operator">||</span> <span class="ruby-constant">ENV</span>[<span class="ruby-value str">'USERNAME'</span>] <span class="ruby-operator">||</span> <span class="ruby-value str">"unknown"</span>
179: 
180: <span class="ruby-ivar">@open_connections</span> = <span class="ruby-value">0</span>
181: <span class="ruby-ivar">@pending_sessions</span> = []
182: <span class="ruby-ivar">@session_mutex</span> = <span class="ruby-constant">Mutex</span>.<span class="ruby-identifier">new</span>
183: 
184: <span class="ruby-identifier">options</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">opt</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">send</span>(<span class="ruby-node">"#{opt}="</span>, <span class="ruby-identifier">value</span>) }
185: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <h2>Public instance methods</h2> + <div class='method public-instance' id='method-M000074'> + <a name='M000074'> </a> + <div class='synopsis'> + <span class='name'>close</span> + <span class='arguments'>()</span> + </div> + <div class='description'> + <p> + Closes the multi-session by shutting down all open server sessions, and the + default gateway (if one was specified using <a + href="Session.html#M000068">via</a>). Note that other gateway connections + (e.g., those passed to <a href="Session.html#M000069">use</a> directly) + will <em>not</em> be closed by this method, and must be managed externally. + </p> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000074-source'); return false"> + [show source] + </a> + <pre id='M000074-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 402</span>
402: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">close</span>
403: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">close_channels</span> }
404: <span class="ruby-identifier">loop</span>(<span class="ruby-value">0</span>) { <span class="ruby-identifier">busy?</span>(<span class="ruby-keyword kw">true</span>) }
405: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">close</span> }
406: <span class="ruby-identifier">default_gateway</span>.<span class="ruby-identifier">shutdown!</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">default_gateway</span>
407: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000067'> + <a name='M000067'> </a> + <div class='synopsis'> + <span class='name'>group</span> + <span class='arguments'>(*args) {|self| ...}</span> + </div> + <div class='description'> + <p> + At its simplest, this associates a named group with a server definition. It + can be used in either of two ways: + </p> + <p> + 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 <a + href="Session.html#M000069">use</a>): + </p> + <pre>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]</pre> + <p> + 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 <a + href="Session.html#M000069">use</a> will automatically associate the new + server definition with those groups. You can nest <a + href="Session.html#M000067">group</a> calls, too, which will aggregate the + group definitions. + </p> + <pre>session.group :rackspace, :backup do
 session.use 'host1', 'user1'
 session.group :xen do
 session.use 'host2', 'user2'
 end
end</pre> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000067-source'); return false"> + [show source] + </a> + <pre id='M000067-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 213</span>
213: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">group</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">args</span>)
214: <span class="ruby-identifier">mapping</span> = <span class="ruby-identifier">args</span>.<span class="ruby-identifier">last</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">?</span> <span class="ruby-identifier">args</span>.<span class="ruby-identifier">pop</span> <span class="ruby-operator">:</span> {}
215: 
216: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">mapping</span>.<span class="ruby-identifier">any?</span> <span class="ruby-operator">&&</span> <span class="ruby-identifier">block_given?</span>
217: <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">"must provide group mapping OR block, not both"</span>
218: <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">block_given?</span>
219: <span class="ruby-keyword kw">begin</span>
220: <span class="ruby-identifier">saved_groups</span> = <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">dup</span>
221: <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">concat</span>(<span class="ruby-identifier">args</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">a</span><span class="ruby-operator">|</span> <span class="ruby-identifier">a</span>.<span class="ruby-identifier">to_sym</span> }).<span class="ruby-identifier">uniq!</span>
222: <span class="ruby-keyword kw">yield</span> <span class="ruby-keyword kw">self</span>
223: <span class="ruby-keyword kw">ensure</span>
224: <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">replace</span>(<span class="ruby-identifier">saved_groups</span>)
225: <span class="ruby-keyword kw">end</span>
226: <span class="ruby-keyword kw">else</span>
227: <span class="ruby-identifier">mapping</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
228: (<span class="ruby-identifier">open_groups</span> <span class="ruby-operator">+</span> <span class="ruby-constant">Array</span>(<span class="ruby-identifier">key</span>)).<span class="ruby-identifier">uniq</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">grp</span><span class="ruby-operator">|</span>
229: <span class="ruby-identifier">groups</span>[<span class="ruby-identifier">grp</span>.<span class="ruby-identifier">to_sym</span>].<span class="ruby-identifier">concat</span>(<span class="ruby-constant">Array</span>(<span class="ruby-identifier">value</span>))
230: <span class="ruby-keyword kw">end</span>
231: <span class="ruby-keyword kw">end</span>
232: <span class="ruby-keyword kw">end</span>
233: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000075'> + <a name='M000075'> </a> + <div class='synopsis'> + <span class='name'>loop</span> + <span class='arguments'>(wait=nil, &block)</span> + </div> + <div class='description'> + <p> + Run the aggregated event loop for all open server sessions, until the given + block returns <tt>false</tt>. If no block is given, the loop will run for + as long as busy? returns <tt>true</tt> (in other words, for as long as + there are any (non-invisible) channels open). + </p> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000075-source'); return false"> + [show source] + </a> + <pre id='M000075-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 415</span>
415: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">loop</span>(<span class="ruby-identifier">wait</span>=<span class="ruby-keyword kw">nil</span>, <span class="ruby-operator">&</span><span class="ruby-identifier">block</span>)
416: <span class="ruby-identifier">running</span> = <span class="ruby-identifier">block</span> <span class="ruby-operator">||</span> <span class="ruby-constant">Proc</span>.<span class="ruby-identifier">new</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">c</span><span class="ruby-operator">|</span> <span class="ruby-identifier">busy?</span> }
417: <span class="ruby-identifier">loop_forever</span> { <span class="ruby-keyword kw">break</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">process</span>(<span class="ruby-identifier">wait</span>, <span class="ruby-operator">&</span><span class="ruby-identifier">running</span>) }
418: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000076'> + <a name='M000076'> </a> + <div class='synopsis'> + <span class='name'>loop_forever</span> + <span class='arguments'>(wait=nil, &block)</span> + </div> + <div class='description'> + <p> + Alias for <a href="Session.html#M000075">loop</a> + </p> + </div> + </div> + <div class='method public-instance' id='method-M000073'> + <a name='M000073'> </a> + <div class='synopsis'> + <span class='name'>on</span> + <span class='arguments'>(*servers) {|subsession if block_given?| ...}</span> + </div> + <div class='description'> + <p> + Works as <a href="Session.html#M000072">with</a>, but for specific servers + rather than groups. It will return a new subsession (<a + href="Subsession.html">Net::SSH::Multi::Subsession</a>) consisting of the + given servers. (Note that it requires that the servers in question have + been created via calls to <a href="Session.html#M000069">use</a> 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. + </p> + <pre>srv1 = session.use('host1', 'user')
srv2 = session.use('host2', 'user')
# ...
session.on(srv1, srv2).exec('hostname')</pre> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000073-source'); return false"> + [show source] + </a> + <pre id='M000073-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 392</span>
392: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">servers</span>)
393: <span class="ruby-identifier">subsession</span> = <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">servers</span>)
394: <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">subsession</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>
395: <span class="ruby-identifier">subsession</span>
396: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000077'> + <a name='M000077'> </a> + <div class='synopsis'> + <span class='name'>process</span> + <span class='arguments'>(wait=nil, &block)</span> + </div> + <div class='description'> + <p> + Run a single iteration of the aggregated event loop for all open server + sessions. The <tt>wait</tt> parameter indicates how long to wait for an + event to appear on any of the different sessions; <tt>nil</tt> (the + default) means “wait forever”. If the block is given, then it + will be used to determine whether <a + href="Session.html#M000077">process</a> returns <tt>true</tt> (the block + did not return <tt>false</tt>), or <tt>false</tt> (the block returned + <tt>false</tt>). + </p> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000077-source'); return false"> + [show source] + </a> + <pre id='M000077-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 426</span>
426: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">process</span>(<span class="ruby-identifier">wait</span>=<span class="ruby-keyword kw">nil</span>, <span class="ruby-operator">&</span><span class="ruby-identifier">block</span>)
427: <span class="ruby-identifier">realize_pending_connections!</span>
428: <span class="ruby-identifier">wait</span> = <span class="ruby-ivar">@connect_threads</span>.<span class="ruby-identifier">any?</span> <span class="ruby-value">? </span><span class="ruby-value">0</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">wait</span>
429: 
430: <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">false</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">preprocess</span>(<span class="ruby-operator">&</span><span class="ruby-identifier">block</span>)
431: 
432: <span class="ruby-identifier">readers</span> = <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">s</span><span class="ruby-operator">|</span> <span class="ruby-identifier">s</span>.<span class="ruby-identifier">readers</span> }.<span class="ruby-identifier">flatten</span>
433: <span class="ruby-identifier">writers</span> = <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">s</span><span class="ruby-operator">|</span> <span class="ruby-identifier">s</span>.<span class="ruby-identifier">writers</span> }.<span class="ruby-identifier">flatten</span>
434: 
435: <span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>, = <span class="ruby-constant">IO</span>.<span class="ruby-identifier">select</span>(<span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>, <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">wait</span>)
436: 
437: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">readers</span>
438: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">postprocess</span>(<span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>)
439: <span class="ruby-keyword kw">else</span>
440: <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span>
441: <span class="ruby-keyword kw">end</span>
442: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000070'> + <a name='M000070'> </a> + <div class='synopsis'> + <span class='name'>servers</span> + <span class='arguments'>()</span> + </div> + <div class='description'> + <p> + Essentially an alias for <a href="Session.html#M000071">servers_for</a> + without any arguments. This is used primarily to satistfy the expectations + of the <a href="SessionActions.html">Net::SSH::Multi::SessionActions</a> + module. + </p> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000070-source'); return false"> + [show source] + </a> + <pre id='M000070-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 293</span>
293: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">servers</span>
294: <span class="ruby-identifier">servers_for</span>
295: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000071'> + <a name='M000071'> </a> + <div class='synopsis'> + <span class='name'>servers_for</span> + <span class='arguments'>(*criteria)</span> + </div> + <div class='description'> + <p> + Returns the set of servers that match the given criteria. It can be used in + any (or all) of three ways. + </p> + <p> + First, you can omit any arguments. In this case, the full list of servers + will be returned. + </p> + <pre>all = session.servers_for</pre> + <p> + 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). + </p> + <pre>servers = session.servers_for(:app, :db)</pre> + <p> + 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 <em>not</em> match). Properties are described + when the server is defined (via the :properties key): + </p> + <pre>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 } })</pre> + <p> + You can, naturally, combine these methods: + </p> + <pre># 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 } })</pre> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000071-source'); return false"> + [show source] + </a> + <pre id='M000071-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 334</span>
334: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">servers_for</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">criteria</span>)
335: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">empty?</span>
336: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">flatten</span>
337: <span class="ruby-keyword kw">else</span>
338: <span class="ruby-comment cmt"># normalize the criteria list, so that every entry is a key to a</span>
339: <span class="ruby-comment cmt"># criteria hash (possibly empty).</span>
340: <span class="ruby-identifier">criteria</span> = <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">inject</span>({}) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">hash</span>, <span class="ruby-identifier">entry</span><span class="ruby-operator">|</span>
341: <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">entry</span>
342: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">Hash</span> <span class="ruby-keyword kw">then</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">entry</span>)
343: <span class="ruby-keyword kw">else</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">entry</span> =<span class="ruby-operator">></span> {})
344: <span class="ruby-keyword kw">end</span>
345: <span class="ruby-keyword kw">end</span>
346: 
347: <span class="ruby-identifier">list</span> = <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">inject</span>([]) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">aggregator</span>, (<span class="ruby-identifier">group</span>, <span class="ruby-identifier">properties</span>)<span class="ruby-operator">|</span>
348: <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">"the value for any group must be a Hash, but got a #{properties.class} for #{group.inspect}"</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">properties</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>)
349: <span class="ruby-identifier">bad_keys</span> = <span class="ruby-identifier">properties</span>.<span class="ruby-identifier">keys</span> <span class="ruby-operator">-</span> [<span class="ruby-identifier">:only</span>, <span class="ruby-identifier">:except</span>]
350: <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">"unknown constraint(s) #{bad_keys.inspect} for #{group.inspect}"</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">bad_keys</span>.<span class="ruby-identifier">empty?</span>
351: 
352: <span class="ruby-identifier">servers</span> = <span class="ruby-identifier">groups</span>[<span class="ruby-identifier">group</span>].<span class="ruby-identifier">select</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span>
353: (<span class="ruby-identifier">properties</span>[<span class="ruby-identifier">:only</span>] <span class="ruby-operator">||</span> {}).<span class="ruby-identifier">all?</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">prop</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>[<span class="ruby-identifier">prop</span>] <span class="ruby-operator">==</span> <span class="ruby-identifier">value</span> } <span class="ruby-operator">&&</span>
354: <span class="ruby-operator">!</span>(<span class="ruby-identifier">properties</span>[<span class="ruby-identifier">:except</span>] <span class="ruby-operator">||</span> {}).<span class="ruby-identifier">any?</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">prop</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>[<span class="ruby-identifier">prop</span>] <span class="ruby-operator">==</span> <span class="ruby-identifier">value</span> }
355: <span class="ruby-keyword kw">end</span>
356: 
357: <span class="ruby-identifier">aggregator</span>.<span class="ruby-identifier">concat</span>(<span class="ruby-identifier">servers</span>)
358: <span class="ruby-keyword kw">end</span>
359: 
360: <span class="ruby-identifier">list</span>.<span class="ruby-identifier">uniq</span>
361: <span class="ruby-keyword kw">end</span>
362: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000069'> + <a name='M000069'> </a> + <div class='synopsis'> + <span class='name'>use</span> + <span class='arguments'>(*hosts, &block)</span> + </div> + <div class='description'> + <p> + Defines a new server definition, to be managed by this session. The server + is at the given <tt>host</tt>, and will be connected to as the given + <tt>user</tt>. The other options are passed as-is to the <a + href="../../SSH.html">Net::SSH</a> session constructor. + </p> + <p> + If a default gateway has been specified previously (with <a + href="Session.html#M000068">via</a>) it will be passed to the new server + definition. You can override this by passing a different Net::SSH::Gateway + instance (or <tt>nil</tt>) with the :via key in the <tt>options</tt>. + </p> + <pre>session.use 'host'
session.use 'user@host2', :via => nil
session.use 'host3', :user => "user3", :via => Net::SSH::Gateway.new('gateway.host', 'user')</pre> + <p> + 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. + </p> + <pre>server1, server2 = session.use "host1", "host2"</pre> + <p> + If given a block, this will save the block as a <a + href="DynamicServer.html">Net::SSH::Multi::DynamicServer</a> definition, to + be evaluated lazily the first time the server is needed. The block will + recive any options hash given to <a href="Session.html#M000069">use</a>, + and should return <tt>nil</tt> (if no servers are to be added), a String or + an array of Strings (to be interpreted as a connection specification), or a + <a href="Server.html">Server</a> or an array of Servers. + </p> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000069-source'); return false"> + [show source] + </a> + <pre id='M000069-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 274</span>
274: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">use</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">hosts</span>, <span class="ruby-operator">&</span><span class="ruby-identifier">block</span>)
275: <span class="ruby-identifier">options</span> = <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">last</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">?</span> <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">pop</span> <span class="ruby-operator">:</span> {}
276: <span class="ruby-identifier">options</span> = { <span class="ruby-identifier">:via</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">default_gateway</span> }.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">options</span>)
277: 
278: <span class="ruby-identifier">results</span> = <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">map</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">host</span><span class="ruby-operator">|</span>
279: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">add</span>(<span class="ruby-constant">Server</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">host</span>, <span class="ruby-identifier">options</span>))
280: <span class="ruby-keyword kw">end</span>
281: 
282: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block</span>
283: <span class="ruby-identifier">results</span> <span class="ruby-operator"><<</span> <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">add</span>(<span class="ruby-constant">DynamicServer</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">options</span>, <span class="ruby-identifier">block</span>))
284: <span class="ruby-keyword kw">end</span>
285: 
286: <span class="ruby-identifier">group</span> [] =<span class="ruby-operator">></span> <span class="ruby-identifier">results</span>
287: <span class="ruby-identifier">results</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">></span> <span class="ruby-value">1</span> <span class="ruby-operator">?</span> <span class="ruby-identifier">results</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">results</span>.<span class="ruby-identifier">first</span>
288: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000068'> + <a name='M000068'> </a> + <div class='synopsis'> + <span class='name'>via</span> + <span class='arguments'>(host, user, options={})</span> + </div> + <div class='description'> + <p> + 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. + </p> + <pre>session.via 'gateway.host', 'user'</pre> + <p> + You may override the default gateway on a per-server basis by passing the + :via key to the <a href="Session.html#M000069">use</a> method; see <a + href="Session.html#M000069">use</a> for details. + </p> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000068-source'); return false"> + [show source] + </a> + <pre id='M000068-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 243</span>
243: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">via</span>(<span class="ruby-identifier">host</span>, <span class="ruby-identifier">user</span>, <span class="ruby-identifier">options</span>={})
244: <span class="ruby-ivar">@default_gateway</span> = <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">SSH</span><span class="ruby-operator">::</span><span class="ruby-constant">Gateway</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">host</span>, <span class="ruby-identifier">user</span>, <span class="ruby-identifier">options</span>)
245: <span class="ruby-keyword kw">self</span>
246: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + <div class='method public-instance' id='method-M000072'> + <a name='M000072'> </a> + <div class='synopsis'> + <span class='name'>with</span> + <span class='arguments'>(*groups) {|subsession if block_given?| ...}</span> + </div> + <div class='description'> + <p> + Returns a new <a href="Subsession.html">Net::SSH::Multi::Subsession</a> + instance consisting of the servers that meet the given criteria. If a block + is given, the subsession will be yielded to it. See <a + href="Session.html#M000071">servers_for</a> for a discussion of how these + criteria are interpreted. + </p> + <pre>session.with(:app).exec('hostname')

session.with(:app, :db => { :primary => true }) do |s|
 s.exec 'date'
 s.exec 'uptime'
end</pre> + </div> + <div class='source'> + <a class='source-toggle' href='#' onclick="toggleCode('M000072-source'); return false"> + [show source] + </a> + <pre id='M000072-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 375</span>
375: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">with</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">groups</span>)
376: <span class="ruby-identifier">subsession</span> = <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">servers_for</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">groups</span>))
377: <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">subsession</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>
378: <span class="ruby-identifier">subsession</span>
379: <span class="ruby-keyword kw">end</span></pre> + </div> + </div> + </div> + </div> + </div> + </div> + <div id='footer-push'></div> + </div> + <div id='footer'> + <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a> + </div> + </body> +</html> |