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.

Methods

actions   activate?   handlemsg   load_ddl   new  

Included Modules

Translatable

Attributes

agent_name  [RW] 
config  [R] 
ddl  [R] 
logger  [R] 
meta  [R] 
reply  [RW] 
request  [RW] 
timeout  [R] 

Public Class methods

Returns an array of actions this agent support

[Source]

     # File lib/mcollective/rpc/agent.rb, line 157
157:       def self.actions
158:         public_instance_methods.sort.grep(/_action$/).map do |method|
159:           $1 if method =~ /(.+)_action$/
160:         end
161:       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

[Source]

     # 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 = Util.str_to_bool(Config.instance.pluginconf.fetch("#{agent_name}.activate_agent", true))
148: 
149:         unless 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:         end
152: 
153:         return should_activate
154:       end

[Source]

    # 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

Public Instance methods

[Source]

     # 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 consistent
 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

[Source]

    # 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

[Validate]