Class | MCollective::RPC::Agent |
In: |
lib/mcollective/rpc/agent.rb
|
Parent: | Object |
A wrapper around the traditional agent, it takes care of a lot of the tedious setup you would do for each agent allowing you to just create methods following a naming standard leaving the heavy lifting up to this clas.
See marionette-collective.org/simplerpc/agents.html
It only really makes sense to use this with a Simple RPC client on the other end, basic usage would be:
module MCollective module Agent class Helloworld<RPC::Agent action "hello" do reply[:msg] = "Hello #{request[:name]}" end action "foo" do implemented_by "/some/script.sh" end end end end
If you wish to implement the logic for an action using an external script use the implemented_by method that will cause your script to be run with 2 arguments.
The first argument is a file containing JSON with the request and the 2nd argument is where the script should save its output as a JSON hash.
We also currently have the validation code in here, this will be moved to plugins soon.
agent_name | [RW] | |
config | [R] | |
ddl | [R] | |
logger | [R] | |
meta | [R] | |
reply | [RW] | |
request | [RW] | |
timeout | [R] |
By default RPC Agents support a toggle in the configuration that can enable and disable them based on the agent name
Example an agent called Foo can have:
plugin.foo.activate_agent = false
and this will prevent the agent from loading on this particular machine.
Agents can use the activate_when helper to override this for example:
activate_when do
File.exist?("/usr/bin/puppet")
end
# File lib/mcollective/rpc/agent.rb, line 139 139: def self.activate? 140: agent_name = self.to_s.split("::").last.downcase 141: 142: Log.debug("Starting default activation checks for #{agent_name}") 143: 144: should_activate = Config.instance.pluginconf["#{agent_name}.activate_agent"] 145: 146: if should_activate 147: Log.debug("Found plugin config #{agent_name}.activate_agent with value #{should_activate}") 148: unless should_activate =~ /^1|y|true$/ 149: return false 150: end 151: end 152: 153: return true 154: end
# File lib/mcollective/rpc/agent.rb, line 37 37: def initialize 38: @agent_name = self.class.to_s.split("::").last.downcase 39: 40: load_ddl 41: 42: @logger = Log.instance 43: @config = Config.instance 44: 45: # if we have a global authorization provider enable it 46: # plugins can still override it per plugin 47: self.class.authorized_by(@config.rpcauthprovider) if @config.rpcauthorization 48: 49: startup_hook 50: end
# File lib/mcollective/rpc/agent.rb, line 62 62: def handlemsg(msg, connection) 63: @request = RPC::Request.new(msg, @ddl) 64: @reply = RPC::Reply.new(@request.action, @ddl) 65: 66: begin 67: # Incoming requests need to be validated against the DDL thus reusing 68: # all the work users put into creating DDLs and creating a consistant 69: # quality of input validation everywhere with the a simple once off 70: # investment of writing a DDL 71: @request.validate! 72: 73: # Calls the authorization plugin if any is defined 74: # if this raises an exception we wil just skip processing this 75: # message 76: authorization_hook(@request) if respond_to?("authorization_hook") 77: 78: # Audits the request, currently continues processing the message 79: # we should make this a configurable so that an audit failure means 80: # a message wont be processed by this node depending on config 81: audit_request(@request, connection) 82: 83: before_processing_hook(msg, connection) 84: 85: if respond_to?("#{@request.action}_action") 86: send("#{@request.action}_action") 87: else 88: raise UnknownRPCAction, "Unknown action: #{@request.action}" 89: end 90: rescue RPCAborted => e 91: @reply.fail e.to_s, 1 92: 93: rescue UnknownRPCAction => e 94: @reply.fail e.to_s, 2 95: 96: rescue MissingRPCData => e 97: @reply.fail e.to_s, 3 98: 99: rescue InvalidRPCData, DDLValidationError => e 100: @reply.fail e.to_s, 4 101: 102: rescue UnknownRPCError => e 103: Log.error("%s#%s failed: %s: %s" % [@agent_name, @request.action, e.class, e.to_s]) 104: Log.error(e.backtrace.join("\n\t")) 105: @reply.fail e.to_s, 5 106: 107: rescue Exception => e 108: Log.error("%s#%s failed: %s: %s" % [@agent_name, @request.action, e.class, e.to_s]) 109: Log.error(e.backtrace.join("\n\t")) 110: @reply.fail e.to_s, 5 111: 112: end 113: 114: after_processing_hook 115: 116: if @request.should_respond? 117: return @reply.to_hash 118: else 119: Log.debug("Client did not request a response, surpressing reply") 120: return nil 121: end 122: end
# File lib/mcollective/rpc/agent.rb, line 52 52: def load_ddl 53: @ddl = DDL.new(@agent_name, :agent) 54: @meta = @ddl.meta 55: @timeout = @meta[:timeout] || 10 56: 57: rescue Exception => e 58: Log.error("Failed to load DDL for the '%s' agent, DDLs are required: %s: %s" % [@agent_name, e.class, e.to_s]) 59: raise DDLValidationError 60: end