1 <?xml version="1.0" encoding="iso-8859-1"?>
3 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
8 <title>Class: MCollective::RPC::ActionRunner</title>
9 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10 <meta http-equiv="Content-Script-Type" content="text/javascript" />
11 <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
12 <script type="text/javascript">
15 function popupCode( url ) {
16 window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
19 function toggleCode( id ) {
20 if ( document.getElementById )
21 elem = document.getElementById( id );
22 else if ( document.all )
23 elem = eval( "document.all." + id );
27 elemStyle = elem.style;
29 if ( elemStyle.display != "block" ) {
30 elemStyle.display = "block"
32 elemStyle.display = "none"
38 // Make codeblocks hidden by default
39 document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
49 <div id="classHeader">
50 <table class="header-table">
51 <tr class="top-aligned-row">
52 <td><strong>Class</strong></td>
53 <td class="class-name-in-header">MCollective::RPC::ActionRunner</td>
55 <tr class="top-aligned-row">
56 <td><strong>In:</strong></td>
58 <a href="../../../files/lib/mcollective/rpc/actionrunner_rb.html">
59 lib/mcollective/rpc/actionrunner.rb
65 <tr class="top-aligned-row">
66 <td><strong>Parent:</strong></td>
73 <!-- banner header -->
75 <div id="bodyContent">
79 <div id="contextContent">
81 <div id="description">
83 A helper used by RPC::Agent#implemented_by to delegate an action to an
84 external script. At present only JSON based serialization is supported in
85 future ones based on key=val pairs etc will be added
88 It serializes the request object into an input file and creates an empty
89 output file. It then calls the external command reading the output file at
93 any STDERR gets logged at error level and any STDOUT gets logged at info
97 It will interpret the exit code from the application the same way <a
98 href="Reply.html#M000074">RPC::Reply#fail</a>! and fail handles their codes
99 creating a consistent interface, the message part of the fail message will
103 Generally externals should just exit with code 1 on failure and print to
104 STDERR, this is exactly what Perl die() does and translates perfectly to
108 It uses the <a href="../Shell.html">MCollective::Shell</a> wrapper to call
109 the external application
117 <div id="method-list">
118 <h3 class="section-bar">Methods</h3>
120 <div class="name-list">
121 <a href="#M000066">canrun?</a>
122 <a href="#M000063">load_json_results</a>
123 <a href="#M000062">load_results</a>
124 <a href="#M000059">new</a>
125 <a href="#M000069">path_to_command</a>
126 <a href="#M000060">run</a>
127 <a href="#M000065">save_json_request</a>
128 <a href="#M000064">saverequest</a>
129 <a href="#M000061">shell</a>
130 <a href="#M000068">tempfile</a>
131 <a href="#M000067">to_s</a>
146 <div id="attribute-list">
147 <h3 class="section-bar">Attributes</h3>
149 <div class="name-list">
151 <tr class="top-aligned-row context-row">
152 <td class="context-item-name">action</td>
153 <td class="context-item-value"> [R] </td>
154 <td class="context-item-desc"></td>
156 <tr class="top-aligned-row context-row">
157 <td class="context-item-name">agent</td>
158 <td class="context-item-value"> [R] </td>
159 <td class="context-item-desc"></td>
161 <tr class="top-aligned-row context-row">
162 <td class="context-item-name">command</td>
163 <td class="context-item-value"> [R] </td>
164 <td class="context-item-desc"></td>
166 <tr class="top-aligned-row context-row">
167 <td class="context-item-name">format</td>
168 <td class="context-item-value"> [R] </td>
169 <td class="context-item-desc"></td>
171 <tr class="top-aligned-row context-row">
172 <td class="context-item-name">request</td>
173 <td class="context-item-value"> [R] </td>
174 <td class="context-item-desc"></td>
176 <tr class="top-aligned-row context-row">
177 <td class="context-item-name">stderr</td>
178 <td class="context-item-value"> [R] </td>
179 <td class="context-item-desc"></td>
181 <tr class="top-aligned-row context-row">
182 <td class="context-item-name">stdout</td>
183 <td class="context-item-value"> [R] </td>
184 <td class="context-item-desc"></td>
192 <!-- if method_list -->
194 <h3 class="section-bar">Public Class methods</h3>
196 <div id="method-M000059" class="method-detail">
197 <a name="M000059"></a>
199 <div class="method-heading">
200 <a href="#M000059" class="method-signature">
201 <span class="method-name">new</span><span class="method-args">(command, request, format=:json)</span>
205 <div class="method-description">
206 <p><a class="source-toggle" href="#"
207 onclick="toggleCode('M000059-source');return false;">[Source]</a></p>
208 <div class="method-source-code" id="M000059-source">
210 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 26</span>
211 26: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">command</span>, <span class="ruby-identifier">request</span>, <span class="ruby-identifier">format</span>=<span class="ruby-identifier">:json</span>)
212 27: <span class="ruby-ivar">@agent</span> = <span class="ruby-identifier">request</span>.<span class="ruby-identifier">agent</span>
213 28: <span class="ruby-ivar">@action</span> = <span class="ruby-identifier">request</span>.<span class="ruby-identifier">action</span>
214 29: <span class="ruby-ivar">@format</span> = <span class="ruby-identifier">format</span>
215 30: <span class="ruby-ivar">@request</span> = <span class="ruby-identifier">request</span>
216 31: <span class="ruby-ivar">@command</span> = <span class="ruby-identifier">path_to_command</span>(<span class="ruby-identifier">command</span>)
217 32: <span class="ruby-ivar">@stdout</span> = <span class="ruby-value str">""</span>
218 33: <span class="ruby-ivar">@stderr</span> = <span class="ruby-value str">""</span>
219 34: <span class="ruby-keyword kw">end</span>
225 <h3 class="section-bar">Public Instance methods</h3>
227 <div id="method-M000066" class="method-detail">
228 <a name="M000066"></a>
230 <div class="method-heading">
231 <a href="#M000066" class="method-signature">
232 <span class="method-name">canrun?</span><span class="method-args">(command)</span>
236 <div class="method-description">
237 <p><a class="source-toggle" href="#"
238 onclick="toggleCode('M000066-source');return false;">[Source]</a></p>
239 <div class="method-source-code" id="M000066-source">
241 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 117</span>
242 117: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">canrun?</span>(<span class="ruby-identifier">command</span>)
243 118: <span class="ruby-constant">File</span>.<span class="ruby-identifier">executable?</span>(<span class="ruby-identifier">command</span>)
244 119: <span class="ruby-keyword kw">end</span>
250 <div id="method-M000063" class="method-detail">
251 <a name="M000063"></a>
253 <div class="method-heading">
254 <a href="#M000063" class="method-signature">
255 <span class="method-name">load_json_results</span><span class="method-args">(file)</span>
259 <div class="method-description">
260 <p><a class="source-toggle" href="#"
261 onclick="toggleCode('M000063-source');return false;">[Source]</a></p>
262 <div class="method-source-code" id="M000063-source">
264 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 91</span>
265 91: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">load_json_results</span>(<span class="ruby-identifier">file</span>)
266 92: <span class="ruby-keyword kw">return</span> {} <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">File</span>.<span class="ruby-identifier">readable?</span>(<span class="ruby-identifier">file</span>)
268 94: <span class="ruby-constant">JSON</span>.<span class="ruby-identifier">load</span>(<span class="ruby-constant">File</span>.<span class="ruby-identifier">read</span>(<span class="ruby-identifier">file</span>)) <span class="ruby-operator">||</span> {}
269 95: <span class="ruby-keyword kw">rescue</span> <span class="ruby-constant">JSON</span><span class="ruby-operator">::</span><span class="ruby-constant">ParserError</span>
271 97: <span class="ruby-keyword kw">end</span>
277 <div id="method-M000062" class="method-detail">
278 <a name="M000062"></a>
280 <div class="method-heading">
281 <a href="#M000062" class="method-signature">
282 <span class="method-name">load_results</span><span class="method-args">(file)</span>
286 <div class="method-description">
287 <p><a class="source-toggle" href="#"
288 onclick="toggleCode('M000062-source');return false;">[Source]</a></p>
289 <div class="method-source-code" id="M000062-source">
291 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 73</span>
292 73: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">load_results</span>(<span class="ruby-identifier">file</span>)
293 74: <span class="ruby-constant">Log</span>.<span class="ruby-identifier">debug</span>(<span class="ruby-node">"Attempting to load results in #{format} format from #{file}"</span>)
295 76: <span class="ruby-identifier">data</span> = {}
297 78: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">respond_to?</span>(<span class="ruby-node">"load_#{format}_results"</span>)
298 79: <span class="ruby-identifier">tempdata</span> = <span class="ruby-identifier">send</span>(<span class="ruby-node">"load_#{format}_results"</span>, <span class="ruby-identifier">file</span>)
300 81: <span class="ruby-identifier">tempdata</span>.<span class="ruby-identifier">each_pair</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">k</span>,<span class="ruby-identifier">v</span><span class="ruby-operator">|</span>
301 82: <span class="ruby-identifier">data</span>[<span class="ruby-identifier">k</span>.<span class="ruby-identifier">to_sym</span>] = <span class="ruby-identifier">v</span>
302 83: <span class="ruby-keyword kw">end</span>
303 84: <span class="ruby-keyword kw">end</span>
305 86: <span class="ruby-identifier">data</span>
306 87: <span class="ruby-keyword kw">rescue</span> <span class="ruby-constant">Exception</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">e</span>
308 89: <span class="ruby-keyword kw">end</span>
314 <div id="method-M000069" class="method-detail">
315 <a name="M000069"></a>
317 <div class="method-heading">
318 <a href="#M000069" class="method-signature">
319 <span class="method-name">path_to_command</span><span class="method-args">(command)</span>
323 <div class="method-description">
324 <p><a class="source-toggle" href="#"
325 onclick="toggleCode('M000069-source');return false;">[Source]</a></p>
326 <div class="method-source-code" id="M000069-source">
328 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 129</span>
329 129: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">path_to_command</span>(<span class="ruby-identifier">command</span>)
330 130: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">command</span>[<span class="ruby-value">0</span>,<span class="ruby-value">1</span>] <span class="ruby-operator">==</span> <span class="ruby-constant">File</span><span class="ruby-operator">::</span><span class="ruby-constant">SEPARATOR</span>
331 131: <span class="ruby-constant">Config</span>.<span class="ruby-identifier">instance</span>.<span class="ruby-identifier">libdir</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">libdir</span><span class="ruby-operator">|</span>
332 132: <span class="ruby-identifier">command_file</span> = <span class="ruby-constant">File</span>.<span class="ruby-identifier">join</span>(<span class="ruby-identifier">libdir</span>, <span class="ruby-value str">"agent"</span>, <span class="ruby-identifier">agent</span>, <span class="ruby-identifier">command</span>)
334 134: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">command_file</span> <span class="ruby-keyword kw">if</span> <span class="ruby-constant">File</span>.<span class="ruby-identifier">exist?</span>(<span class="ruby-identifier">command_file</span>)
335 135: <span class="ruby-keyword kw">end</span>
336 136: <span class="ruby-keyword kw">end</span>
338 138: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">command</span>
339 139: <span class="ruby-keyword kw">end</span>
345 <div id="method-M000060" class="method-detail">
346 <a name="M000060"></a>
348 <div class="method-heading">
349 <a href="#M000060" class="method-signature">
350 <span class="method-name">run</span><span class="method-args">()</span>
354 <div class="method-description">
355 <p><a class="source-toggle" href="#"
356 onclick="toggleCode('M000060-source');return false;">[Source]</a></p>
357 <div class="method-source-code" id="M000060-source">
359 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 36</span>
360 36: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">run</span>
361 37: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">canrun?</span>(<span class="ruby-identifier">command</span>)
362 38: <span class="ruby-constant">Log</span>.<span class="ruby-identifier">warn</span>(<span class="ruby-node">"Cannot run #{to_s}"</span>)
363 39: <span class="ruby-identifier">raise</span> <span class="ruby-constant">RPCAborted</span>, <span class="ruby-node">"Cannot execute #{to_s}"</span>
364 40: <span class="ruby-keyword kw">end</span>
366 42: <span class="ruby-constant">Log</span>.<span class="ruby-identifier">debug</span>(<span class="ruby-node">"Running #{to_s}"</span>)
368 44: <span class="ruby-identifier">request_file</span> = <span class="ruby-identifier">saverequest</span>(<span class="ruby-identifier">request</span>)
369 45: <span class="ruby-identifier">reply_file</span> = <span class="ruby-identifier">tempfile</span>(<span class="ruby-value str">"reply"</span>)
370 46: <span class="ruby-identifier">reply_file</span>.<span class="ruby-identifier">close</span>
372 48: <span class="ruby-identifier">runner</span> = <span class="ruby-identifier">shell</span>(<span class="ruby-identifier">command</span>, <span class="ruby-identifier">request_file</span>.<span class="ruby-identifier">path</span>, <span class="ruby-identifier">reply_file</span>.<span class="ruby-identifier">path</span>)
374 50: <span class="ruby-identifier">runner</span>.<span class="ruby-identifier">runcommand</span>
376 52: <span class="ruby-constant">Log</span>.<span class="ruby-identifier">debug</span>(<span class="ruby-node">"#{command} exited with #{runner.status.exitstatus}"</span>)
378 54: <span class="ruby-identifier">stderr</span>.<span class="ruby-identifier">each_line</span> {<span class="ruby-operator">|</span><span class="ruby-identifier">l</span><span class="ruby-operator">|</span> <span class="ruby-constant">Log</span>.<span class="ruby-identifier">error</span>(<span class="ruby-node">"#{to_s}: #{l.chomp}"</span>)} <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">stderr</span>.<span class="ruby-identifier">empty?</span>
379 55: <span class="ruby-identifier">stdout</span>.<span class="ruby-identifier">each_line</span> {<span class="ruby-operator">|</span><span class="ruby-identifier">l</span><span class="ruby-operator">|</span> <span class="ruby-constant">Log</span>.<span class="ruby-identifier">info</span>(<span class="ruby-node">"#{to_s}: #{l.chomp}"</span>)} <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">stdout</span>.<span class="ruby-identifier">empty?</span>
381 57: {<span class="ruby-identifier">:exitstatus</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">runner</span>.<span class="ruby-identifier">status</span>.<span class="ruby-identifier">exitstatus</span>,
382 58: <span class="ruby-identifier">:stdout</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">runner</span>.<span class="ruby-identifier">stdout</span>,
383 59: <span class="ruby-identifier">:stderr</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">runner</span>.<span class="ruby-identifier">stderr</span>,
384 60: <span class="ruby-identifier">:data</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">load_results</span>(<span class="ruby-identifier">reply_file</span>.<span class="ruby-identifier">path</span>)}
385 61: <span class="ruby-keyword kw">ensure</span>
386 62: <span class="ruby-identifier">request_file</span>.<span class="ruby-identifier">close!</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">request_file</span>.<span class="ruby-identifier">respond_to?</span>(<span class="ruby-value str">"close!"</span>)
387 63: <span class="ruby-identifier">reply_file</span>.<span class="ruby-identifier">close!</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">reply_file</span>.<span class="ruby-identifier">respond_to?</span>(<span class="ruby-value str">"close"</span>)
388 64: <span class="ruby-keyword kw">end</span>
394 <div id="method-M000065" class="method-detail">
395 <a name="M000065"></a>
397 <div class="method-heading">
398 <a href="#M000065" class="method-signature">
399 <span class="method-name">save_json_request</span><span class="method-args">(req)</span>
403 <div class="method-description">
404 <p><a class="source-toggle" href="#"
405 onclick="toggleCode('M000065-source');return false;">[Source]</a></p>
406 <div class="method-source-code" id="M000065-source">
408 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 113</span>
409 113: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">save_json_request</span>(<span class="ruby-identifier">req</span>)
410 114: <span class="ruby-identifier">req</span>.<span class="ruby-identifier">to_json</span>
411 115: <span class="ruby-keyword kw">end</span>
417 <div id="method-M000064" class="method-detail">
418 <a name="M000064"></a>
420 <div class="method-heading">
421 <a href="#M000064" class="method-signature">
422 <span class="method-name">saverequest</span><span class="method-args">(req)</span>
426 <div class="method-description">
427 <p><a class="source-toggle" href="#"
428 onclick="toggleCode('M000064-source');return false;">[Source]</a></p>
429 <div class="method-source-code" id="M000064-source">
431 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 99</span>
432 99: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">saverequest</span>(<span class="ruby-identifier">req</span>)
433 100: <span class="ruby-constant">Log</span>.<span class="ruby-identifier">debug</span>(<span class="ruby-node">"Attempting to save request in #{format} format"</span>)
435 102: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">respond_to?</span>(<span class="ruby-node">"save_#{format}_request"</span>)
436 103: <span class="ruby-identifier">data</span> = <span class="ruby-identifier">send</span>(<span class="ruby-node">"save_#{format}_request"</span>, <span class="ruby-identifier">req</span>)
438 105: <span class="ruby-identifier">request_file</span> = <span class="ruby-identifier">tempfile</span>(<span class="ruby-value str">"request"</span>)
439 106: <span class="ruby-identifier">request_file</span>.<span class="ruby-identifier">puts</span> <span class="ruby-identifier">data</span>
440 107: <span class="ruby-identifier">request_file</span>.<span class="ruby-identifier">close</span>
441 108: <span class="ruby-keyword kw">end</span>
443 110: <span class="ruby-identifier">request_file</span>
444 111: <span class="ruby-keyword kw">end</span>
450 <div id="method-M000061" class="method-detail">
451 <a name="M000061"></a>
453 <div class="method-heading">
454 <a href="#M000061" class="method-signature">
455 <span class="method-name">shell</span><span class="method-args">(command, infile, outfile)</span>
459 <div class="method-description">
460 <p><a class="source-toggle" href="#"
461 onclick="toggleCode('M000061-source');return false;">[Source]</a></p>
462 <div class="method-source-code" id="M000061-source">
464 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 66</span>
465 66: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">shell</span>(<span class="ruby-identifier">command</span>, <span class="ruby-identifier">infile</span>, <span class="ruby-identifier">outfile</span>)
466 67: <span class="ruby-identifier">env</span> = {<span class="ruby-value str">"MCOLLECTIVE_REQUEST_FILE"</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">infile</span>,
467 68: <span class="ruby-value str">"MCOLLECTIVE_REPLY_FILE"</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">outfile</span>}
469 70: <span class="ruby-constant">Shell</span>.<span class="ruby-identifier">new</span>(<span class="ruby-node">"#{command} #{infile} #{outfile}"</span>, <span class="ruby-identifier">:cwd</span> =<span class="ruby-operator">></span> <span class="ruby-constant">Dir</span>.<span class="ruby-identifier">tmpdir</span>, <span class="ruby-identifier">:stdout</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">stdout</span>, <span class="ruby-identifier">:stderr</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">stderr</span>, <span class="ruby-identifier">:environment</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">env</span>)
470 71: <span class="ruby-keyword kw">end</span>
476 <div id="method-M000068" class="method-detail">
477 <a name="M000068"></a>
479 <div class="method-heading">
480 <a href="#M000068" class="method-signature">
481 <span class="method-name">tempfile</span><span class="method-args">(prefix)</span>
485 <div class="method-description">
486 <p><a class="source-toggle" href="#"
487 onclick="toggleCode('M000068-source');return false;">[Source]</a></p>
488 <div class="method-source-code" id="M000068-source">
490 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 125</span>
491 125: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">tempfile</span>(<span class="ruby-identifier">prefix</span>)
492 126: <span class="ruby-constant">Tempfile</span>.<span class="ruby-identifier">new</span>(<span class="ruby-node">"mcollective_#{prefix}"</span>, <span class="ruby-constant">Dir</span>.<span class="ruby-identifier">tmpdir</span>)
493 127: <span class="ruby-keyword kw">end</span>
499 <div id="method-M000067" class="method-detail">
500 <a name="M000067"></a>
502 <div class="method-heading">
503 <a href="#M000067" class="method-signature">
504 <span class="method-name">to_s</span><span class="method-args">()</span>
508 <div class="method-description">
509 <p><a class="source-toggle" href="#"
510 onclick="toggleCode('M000067-source');return false;">[Source]</a></p>
511 <div class="method-source-code" id="M000067-source">
513 <span class="ruby-comment cmt"># File lib/mcollective/rpc/actionrunner.rb, line 121</span>
514 121: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">to_s</span>
515 122: <span class="ruby-value str">"%s#%s command: %s"</span> <span class="ruby-operator">%</span> [ <span class="ruby-identifier">agent</span>, <span class="ruby-identifier">action</span>, <span class="ruby-identifier">command</span> ]
516 123: <span class="ruby-keyword kw">end</span>
529 <div id="validator-badges">
530 <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>