class MCollective::RPC::Agent
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 docs.puppetlabs.com/mcollective/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.
Attributes
Public Class Methods
Returns an array of actions this agent support
# File lib/mcollective/rpc/agent.rb 160 def self.actions 161 public_instance_methods.sort.grep(/_action$/).map do |method| 162 $1 if method =~ /(.+)_action$/ 163 end 164 end
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 139 def self.activate? 140 agent_name = self.to_s.split("::").last.downcase 141 config = Config.instance 142 143 Log.debug("Starting default activation checks for #{agent_name}") 144 145 # Check global state to determine if agent should be loaded 146 should_activate = config.activate_agents 147 148 # Check agent specific state to determine if agent should be loaded 149 should_activate = Util.str_to_bool(config.pluginconf.fetch("#{agent_name}.activate_agent", 150 should_activate)) 151 152 unless should_activate 153 Log.debug("Found plugin configuration '#{agent_name}.activate_agent' with value '#{should_activate}'") 154 end 155 156 return should_activate 157 end
# File lib/mcollective/rpc/agent.rb 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
Public Instance Methods
# File lib/mcollective/rpc/agent.rb 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 consistent 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}' for agent '#{@request.agent}'" 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 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