Class: MCollective::RPC::Agent

Inherits:
Object
  • Object
show all
Defined in:
lib/mcollective/rpc/agent.rb

Overview

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
         matadata :name        => "Test SimpleRPC Agent",
                  :description => "A simple test",
                  :author      => "You",
                  :license     => "1.1",
                  :url         => "http://your.com/,
                  :timeout     => 60

         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.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeAgent

Returns a new instance of Agent.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mcollective/rpc/agent.rb', line 44

def initialize
  # Default meta data unset
  @meta = {:timeout     => 10,
           :name        => "Unknown",
           :description => "Unknown",
           :author      => "Unknown",
           :license     => "Unknown",
           :version     => "Unknown",
           :url         => "Unknown"}

  @timeout = meta[:timeout] || 10
  @logger = Log.instance
  @config = Config.instance
  @agent_name = self.class.to_s.split("::").last.downcase

  # Loads the DDL so we can later use it for validation
  # and help generation
  begin
    @ddl = DDL.new(@agent_name)
  rescue Exception => e
    Log.debug("Failed to load DDL for agent: #{e.class}: #{e}")
    @ddl = nil
  end

  # if we have a global authorization provider enable it
  # plugins can still override it per plugin
  self.class.authorized_by(@config.rpcauthprovider) if @config.rpcauthorization

  startup_hook
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



42
43
44
# File 'lib/mcollective/rpc/agent.rb', line 42

def config
  @config
end

#ddlObject (readonly)

Returns the value of attribute ddl.



42
43
44
# File 'lib/mcollective/rpc/agent.rb', line 42

def ddl
  @ddl
end

#loggerObject (readonly)

Returns the value of attribute logger.



42
43
44
# File 'lib/mcollective/rpc/agent.rb', line 42

def logger
  @logger
end

#metaObject

Returns the value of attribute meta.



41
42
43
# File 'lib/mcollective/rpc/agent.rb', line 41

def meta
  @meta
end

#replyObject

Returns the value of attribute reply.



41
42
43
# File 'lib/mcollective/rpc/agent.rb', line 41

def reply
  @reply
end

#requestObject

Returns the value of attribute request.



41
42
43
# File 'lib/mcollective/rpc/agent.rb', line 41

def request
  @request
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



42
43
44
# File 'lib/mcollective/rpc/agent.rb', line 42

def timeout
  @timeout
end

Class Method Details

.actionsObject

Returns an array of actions this agent support



176
177
178
179
180
# File 'lib/mcollective/rpc/agent.rb', line 176

def self.actions
  public_instance_methods.sort.grep(/_action$/).map do |method|
    $1 if method =~ /(.+)_action$/
  end
end

.activate?Boolean

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

Returns:

  • (Boolean)


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/mcollective/rpc/agent.rb', line 143

def self.activate?
  agent_name = self.to_s.split("::").last.downcase

  Log.debug("Starting default activation checks for #{agent_name}")

  should_activate = Config.instance.pluginconf["#{agent_name}.activate_agent"]

  if should_activate
    Log.debug("Found plugin config #{agent_name}.activate_agent with value #{should_activate}")
    unless should_activate =~ /^1|y|true$/
      return false
    end
  end

  return true
end

.help(template) ⇒ Object

Generates help using the template based on the data created with metadata and input



162
163
164
165
166
167
168
# File 'lib/mcollective/rpc/agent.rb', line 162

def self.help(template)
  if @ddl
    @ddl.help(template)
  else
    "No DDL defined"
  end
end

Instance Method Details

#handlemsg(msg, connection) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/mcollective/rpc/agent.rb', line 75

def handlemsg(msg, connection)
  @request = RPC.request(msg)
  @reply = RPC.reply

  begin
    # Calls the authorization plugin if any is defined
    # if this raises an exception we wil just skip processing this
    # message
    authorization_hook(@request) if respond_to?("authorization_hook")


    # Audits the request, currently continues processing the message
    # we should make this a configurable so that an audit failure means
    # a message wont be processed by this node depending on config
    audit_request(@request, connection)

    before_processing_hook(msg, connection)

    if respond_to?("#{@request.action}_action")
      send("#{@request.action}_action")
    else
      raise UnknownRPCAction, "Unknown action: #{@request.action}"
    end
  rescue RPCAborted => e
    @reply.fail e.to_s, 1

  rescue UnknownRPCAction => e
    @reply.fail e.to_s, 2

  rescue MissingRPCData => e
    @reply.fail e.to_s, 3

  rescue InvalidRPCData => e
    @reply.fail e.to_s, 4

  rescue UnknownRPCError => e
    @reply.fail e.to_s, 5

  rescue Exception => e
    @reply.fail e.to_s, 5

  end

  after_processing_hook

  if @request.should_respond?
    return @reply.to_hash
  else
    Log.debug("Client did not request a response, surpressing reply")
    return nil
  end
end

#helpObject

to auto generate help



171
172
173
# File 'lib/mcollective/rpc/agent.rb', line 171

def help
  self.help("#{@config[:configdir]}/rpc-help.erb")
end