Class: MCollective::RPC::ActionRunner
- Inherits:
-
Object
- Object
- MCollective::RPC::ActionRunner
- Defined in:
- lib/mcollective/rpc/actionrunner.rb
Overview
A helper used by RPC::Agent#implemented_by to delegate an action to an external script. At present only JSON based serialization is supported in future ones based on key=val pairs etc will be added
It serializes the request object into an input file and creates an empty output file. It then calls the external command reading the output file at the end.
any STDERR gets logged at error level and any STDOUT gets logged at info level.
It will interpret the exit code from the application the same way RPC::Reply#fail! and #fail handles their codes creating a consistent interface, the message part of the fail message will come from STDERR
Generally externals should just exit with code 1 on failure and print to STDERR, this is exactly what Perl die() does and translates perfectly to our model
It uses the MCollective::Shell wrapper to call the external application
Instance Attribute Summary collapse
-
#action ⇒ Object
readonly
Returns the value of attribute action.
-
#agent ⇒ Object
readonly
Returns the value of attribute agent.
-
#command ⇒ Object
readonly
Returns the value of attribute command.
-
#format ⇒ Object
readonly
Returns the value of attribute format.
-
#request ⇒ Object
readonly
Returns the value of attribute request.
-
#stderr ⇒ Object
readonly
Returns the value of attribute stderr.
-
#stdout ⇒ Object
readonly
Returns the value of attribute stdout.
Instance Method Summary collapse
- #canrun?(command) ⇒ Boolean
-
#initialize(command, request, format = :json) ⇒ ActionRunner
constructor
A new instance of ActionRunner.
- #load_json_results(file) ⇒ Object
- #load_results(file) ⇒ Object
- #path_to_command(command) ⇒ Object
- #run ⇒ Object
- #save_json_request(req) ⇒ Object
- #saverequest(req) ⇒ Object
- #shell(command, infile, outfile) ⇒ Object
- #tempfile(prefix) ⇒ Object
- #to_s ⇒ Object
Constructor Details
#initialize(command, request, format = :json) ⇒ ActionRunner
Returns a new instance of ActionRunner.
26 27 28 29 30 31 32 33 34 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 26 def initialize(command, request, format=:json) @agent = request.agent @action = request.action @format = format @request = request @command = path_to_command(command) @stdout = "" @stderr = "" end |
Instance Attribute Details
#action ⇒ Object (readonly)
Returns the value of attribute action.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def action @action end |
#agent ⇒ Object (readonly)
Returns the value of attribute agent.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def agent @agent end |
#command ⇒ Object (readonly)
Returns the value of attribute command.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def command @command end |
#format ⇒ Object (readonly)
Returns the value of attribute format.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def format @format end |
#request ⇒ Object (readonly)
Returns the value of attribute request.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def request @request end |
#stderr ⇒ Object (readonly)
Returns the value of attribute stderr.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def stderr @stderr end |
#stdout ⇒ Object (readonly)
Returns the value of attribute stdout.
24 25 26 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 24 def stdout @stdout end |
Instance Method Details
#canrun?(command) ⇒ Boolean
117 118 119 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 117 def canrun?(command) File.executable?(command) end |
#load_json_results(file) ⇒ Object
91 92 93 94 95 96 97 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 91 def load_json_results(file) return {} unless File.readable?(file) JSON.parse(File.read(file)) || {} rescue JSON::ParserError {} end |
#load_results(file) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 73 def load_results(file) Log.debug("Attempting to load results in #{format} format from #{file}") data = {} if respond_to?("load_#{format}_results") tempdata = send("load_#{format}_results", file) tempdata.each_pair do |k, v| data[k.to_sym] = v end end data rescue Exception # rubocop:disable Lint/RescueException {} end |
#path_to_command(command) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 129 def path_to_command(command) return command if Util.absolute_path?(command) Config.instance.libdir.each do |libdir| command_file_old = File.join(libdir, "agent", agent, command) command_file_new = File.join(libdir, "mcollective", "agent", agent, command) command_file_old_exists = File.exist?(command_file_old) command_file_new_exists = File.exist?(command_file_new) if command_file_new_exists && command_file_old_exists Log.debug("Found 'implemented_by' scripts found in two locations #{command_file_old} and #{command_file_new}") Log.debug("Running script: #{command_file_new}") return command_file_new elsif command_file_old_exists Log.debug("Running script: #{command_file_old}") return command_file_old elsif command_file_new_exists Log.debug("Running script: #{command_file_new}") return command_file_new end end Log.warn("No script found for: #{command}") command end |
#run ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 36 def run unless canrun?(command) Log.warn("Cannot run #{self}") raise RPCAborted, "Cannot execute #{self}" end Log.debug("Running #{self}") request_file = saverequest(request) reply_file = tempfile("reply") reply_file.close runner = shell(command, request_file.path, reply_file.path) runner.runcommand Log.debug("#{command} exited with #{runner.status.exitstatus}") stderr.each_line {|l| Log.error("#{self}: #{l.chomp}")} unless stderr.empty? stdout.each_line {|l| Log.info("#{self}: #{l.chomp}")} unless stdout.empty? {:exitstatus => runner.status.exitstatus, :stdout => runner.stdout, :stderr => runner.stderr, :data => load_results(reply_file.path)} ensure request_file.close! if request_file.respond_to?("close!") reply_file.close! if reply_file.respond_to?("close") end |
#save_json_request(req) ⇒ Object
113 114 115 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 113 def save_json_request(req) req.to_json end |
#saverequest(req) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 99 def saverequest(req) Log.debug("Attempting to save request in #{format} format") if respond_to?("save_#{format}_request") data = send("save_#{format}_request", req) request_file = tempfile("request") request_file.puts data request_file.close end request_file end |
#shell(command, infile, outfile) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 66 def shell(command, infile, outfile) env = {"MCOLLECTIVE_REQUEST_FILE" => infile, "MCOLLECTIVE_REPLY_FILE" => outfile} Shell.new("#{command} #{infile} #{outfile}", :cwd => Dir.tmpdir, :stdout => stdout, :stderr => stderr, :environment => env) end |
#tempfile(prefix) ⇒ Object
125 126 127 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 125 def tempfile(prefix) Tempfile.new("mcollective_#{prefix}", Dir.tmpdir) end |
#to_s ⇒ Object
121 122 123 |
# File 'lib/mcollective/rpc/actionrunner.rb', line 121 def to_s "%s#%s command: %s" % [agent, action, command] end |