3 title: Basic Agents and Clients
5 [SimpleRPCIntroduction]: /mcollective/simplerpc/
9 You must use [SimpleRPC][SimpleRPCIntroduction] for writing agents and clients. SimpleRPC is a framework that wraps the core MCollective client and agent structures in a lot of helpful convention and tools.
11 **The approach to developing agents and clients documented below is not supported post version 2.0.0 and the functionality will be removed for the next major release.**
15 Writing agents for mcollective is simple, we'll write a simple _echo_ agent as well as a cli tool to communicate with it that supports discovery, filtering and more.
17 The agent will send back everything that got sent to it, not overly useful but enough to demonstrate the concepts.
21 Agents go into a directory configured in the _server.cfg_ using the _libdir_ directive. You should have _mcollective/agent_ directory under that, restart the daemon when you've put it there.
23 Create a file echo.rb with the following, I'll walk through each part:
25 {% highlight ruby linenos %}
30 attr_reader :timeout, :meta
34 @meta = {:license => "Apache License, Version 2",
35 :author => "R.I.Pienaar <rip@devco.net>",
39 def handlemsg(msg, stomp)
48 Simple agent that just sends the body of any request back
56 Once you have it running you can test your agent works as below, we'll send the word _hello_ to the agent and we'll see if we get it back:
58 {% highlight console %}
59 % /usr/sbin/mc-call-agent --config etc/client.cfg --agent echo --arg hello
60 Determining the amount of hosts matching filter for 2 seconds .... 1
65 ---- stomp call summary ----
67 Start Time: Tue Nov 03 23:18:40 +0000 2009
68 Discovery Time: 2001.65ms
75 Each agent should be wrapped in a module and class as below, this will create an agent called _echo_ and should live in a file called _agents/echo.rb_.
87 Every agent needs to specify a timeout and meta data. The timeout gets used by the app server to kill off agents that is taking too long to finish.
89 Meta data contains some information about the licence, author and version of the agent. Right now the information is free-form but I suggest supplying at the very least the details below as we'll start enforcing the existence of it in future.
92 attr_reader :timeout, :meta
96 @meta = {:license => "Apache License, Version 2",
97 :author => "R.I.Pienaar <rip@devco.net>",
102 ### Handling incoming messages
103 You do not need to be concerned with filtering, authentication, authorization etc when writing agents - the app server takes care of all of that for you.
105 Whenever a message for your agent pass all the checks it will be passed to you via the _handlemsg_ method.
108 def handlemsg(msg, stomp)
113 The msg will be a hash with several keys giving you information about sender, hashes, time it was sent and so forth, in our case we just want to know about the body and we're sending it right back as a return value.
116 We keep help information, not used right now but future version of the code will have a simple way to get help for each agent, the intent is that inputs, outputs and behavior to all agents would be described in this.
124 Simple agent that just sends the body of any request back
129 ## More complex agents
130 As you write more complex agents and clients you might find the need to have a few separate files make up your agent, you can drop these files into a directory named _util_ under the plugins (that is, at the same level of the agent folder, so as _/usr/libexec/mcollective/mcollective/util_ at the time of writing).
132 Create the _util_ folder if needed.
134 The classes should be _MCollective::Util::Yourclass_ and you should use the following construct to require them from disk:
137 MCollective::Util.loadclass("MCollective::Util::Yourclass")
140 Create _util/yourclass.rb_ with this content :
146 # The class definition here
152 _loadclass_ on _Yourclass_ will automatically search for a _yourclass.rb_ file (lowercase).
154 At present simply requiring them will work and we'll hope to maintain that but to be 100% future safe use this method.
157 It also loads modules in exactly the same way.
160 We provide a client library that abstracts away a lot of the work in writing simple attractive cli frontends to your agents that supports discovery, filtering, generates help etc. The client lib is functional but we will improve/refactor the options parsing a bit in future.
162 {% highlight ruby linenos %}
165 require 'mcollective'
167 oparser = MCollective::Optionparser.new({}, "filter")
169 options = oparser.parse{|parser, options|
170 parser.define_head "Tester for the echo agent"
171 parser.banner = "Usage: mc-echo [options] msg"
177 puts("Please specify a message to send")
182 options[:filter]["agent"] = "echo"
184 client = MCollective::Client.new(options[:config])
186 stats = client.discovered_req(msg, "echo", options) do |resp|
189 printf("%30s> %s\n", resp[:senderid], resp[:body])
191 rescue Exception => e
192 puts("Failed to contact any agents: #{e}")
196 client.display_stats(stats, options)
199 We can test it works as below:
201 {% highlight console %}
202 % ./mc-echo --config etc/client.cfg "hello world"
203 Determining the amount of hosts matching filter for 2 seconds .... 1
205 devel.your.com> hello world
207 Finished processing 1 / 1 hosts in 45.02 ms
212 {% highlight console %}
213 % ./mc-echo --config etc/client.cfg "hello world" -v
214 Determining the amount of hosts matching filter for 2 seconds .... 1
216 devel.your.com> hello world
218 ---- stomp call summary ----
220 Start Time: Tue Nov 03 23:28:34 +0000 2009
221 Discovery Time: 2002.27ms
223 Total Time: 2048.11ms
226 Discovery and filtering:
228 {% highlight console %}
229 % ./mc-echo --config etc/client.cfg "hello world" --with-fact country=au
231 Failed to contact any agents: No matching clients found
233 % ./mc-echo --config etc/client.cfg "hello world" --with-fact country=uk
234 Determining the amount of hosts matching filter for 2 seconds .... 1
236 devel.your.com> hello world
238 Finished processing 1 / 1 hosts in 38.77 ms
243 {% highlight console %}
245 Usage: mc-echo [options] msg
246 Tester for the echo agent
249 -c, --config FILE Load configuratuion from file rather than default
250 --dt SECONDS Timeout for doing discovery
252 -t, --timeout SECONDS Timeout for calling remote agents
253 -q, --quiet Do not be verbose
254 -v, --verbose Be verbose
255 -h, --help Display this screen
258 --wf, --with-fact fact=val Match hosts with a certain fact
259 --wc, --with-class CLASS Match hosts with a certain configuration management class
260 --wa, --with-agent AGENT Match hosts with a certain agent
261 --wi, --with-identity IDENT Match hosts with a certain configured identity