| 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 142
142: def self.activate?
143: agent_name = self.to_s.split("::").last.downcase
144:
145: log_code(:PLMC37, "Starting default activation checks for the '%{agent}' agent", :debug, :agent => agent_name)
146:
147: should_activate = Config.instance.pluginconf["#{agent_name}.activate_agent"]
148:
149: if should_activate
150: log_code(:PLMC38, "Found plugin configuration '%{agent}.activate_agent' with value '%{should_activate}'", :debug, :agent => agent_name, :should_activate => should_activate)
151:
152: unless should_activate =~ /^1|y|true$/
153: return false
154: end
155: end
156:
157: return true
158: end
# File lib/mcollective/rpc/agent.rb, line 40
40: def initialize
41: @agent_name = self.class.to_s.split("::").last.downcase
42:
43: load_ddl
44:
45: @logger = Log.instance
46: @config = Config.instance
47:
48: # if we have a global authorization provider enable it
49: # plugins can still override it per plugin
50: self.class.authorized_by(@config.rpcauthprovider) if @config.rpcauthorization
51:
52: startup_hook
53: end
# File lib/mcollective/rpc/agent.rb, line 64
64: def handlemsg(msg, connection)
65: @request = RPC::Request.new(msg, @ddl)
66: @reply = RPC::Reply.new(@request.action, @ddl)
67:
68: begin
69: # Incoming requests need to be validated against the DDL thus reusing
70: # all the work users put into creating DDLs and creating a consistant
71: # quality of input validation everywhere with the a simple once off
72: # investment of writing a DDL
73: @request.validate!
74:
75: # Calls the authorization plugin if any is defined
76: # if this raises an exception we wil just skip processing this
77: # message
78: authorization_hook(@request) if respond_to?("authorization_hook")
79:
80: # Audits the request, currently continues processing the message
81: # we should make this a configurable so that an audit failure means
82: # a message wont be processed by this node depending on config
83: audit_request(@request, connection)
84:
85: before_processing_hook(msg, connection)
86:
87: if respond_to?("#{@request.action}_action")
88: send("#{@request.action}_action")
89: else
90: log_code(:PLMC36, "Unknown action '%{action}' for agent '%{agent}'", :warn, :action => @request.action, :agent => @request.agent)
91: raise UnknownRPCAction, "Unknown action '#{@request.action}' for agent '#{@request.agent}'"
92: end
93: rescue RPCAborted => e
94: @reply.fail e.to_s, 1
95:
96: rescue UnknownRPCAction => e
97: @reply.fail e.to_s, 2
98:
99: rescue MissingRPCData => e
100: @reply.fail e.to_s, 3
101:
102: rescue InvalidRPCData, DDLValidationError => e
103: @reply.fail e.to_s, 4
104:
105: rescue UnknownRPCError => e
106: Log.error("%s#%s failed: %s: %s" % [@agent_name, @request.action, e.class, e.to_s])
107: Log.error(e.backtrace.join("\n\t"))
108: @reply.fail e.to_s, 5
109:
110: rescue Exception => e
111: Log.error("%s#%s failed: %s: %s" % [@agent_name, @request.action, e.class, e.to_s])
112: Log.error(e.backtrace.join("\n\t"))
113: @reply.fail e.to_s, 5
114:
115: end
116:
117: after_processing_hook
118:
119: if @request.should_respond?
120: return @reply.to_hash
121: else
122: log_code(:PLMC35, "Client did not request a response, surpressing reply", :debug)
123: return nil
124: end
125: end
# File lib/mcollective/rpc/agent.rb, line 55
55: def load_ddl
56: @ddl = DDL.new(@agent_name, :agent)
57: @meta = @ddl.meta
58: @timeout = @meta[:timeout] || 10
59:
60: rescue Exception => e
61: DDL.validation_fail!(:PLMC24, "Failed to load DDL for the '%{agent}' agent, DDLs are required: %{error_class}: %{error}", :error, :agent => @agent_name, :error_class => e.class, :error => e.to_s)
62: end