3 title: Single Executable Application Plugin
5 [Clients]: ../../simplerpc/clients.html
6 [SimpleRPCAgents]: ../../simplerpc/agents.html
10 The Marionette Collective 1.1.1 and newer supports a single executable - called
11 mco - and have a plugin type called application that lets you create
12 applications for this single executable.
14 In the past we tended to write small standalone scripts to interact with
15 MCollective, this had a number of issues:
17 * Large number of executables in _/usr/sbin_
18 * Applications behave inconsistently with regard to error handling and reporting
19 * Discovering new applications is difficult since they are all over the filesystem
20 * Installation and packaging of plugins is complex
22 We've attempted to address these concerns by creating a single point of access
23 for all applications - the _mco_ script - with unified help, error reporting and
26 Below you can see the single executable system in use:
28 {% highlight console %}
29 The Marionette Collective version 2.0.0
31 usage: /usr/bin/mco: command <options>
37 help inventory iptables
43 Type 'mco help' for a detailed list of commands and 'mco help command'
44 to get detailed help for a command
48 {% highlight console %}
50 The Marionette Collection version 2.0.0
52 facts Reports on usage for a specific fact
53 filemgr Generic File Manager Client
54 find Find hosts matching criteria
55 help Application list and RPC agent help
56 inventory Shows an inventory for a given node
58 rpc Generic RPC agent client application
61 {% highlight console %}
62 $ mco rpc package status package=zsh
63 Determining the amount of hosts matching filter for 2 seconds .... 51
65 * [ ============================================================> ] 51 / 51
76 :ensure=>"4.2.6-3.el5"}
79 These applications are equivalent to the old mc-rpc and similar applications but without the problem of lots of files in _/usr/sbin_.
82 Applications goes in _libdir/mcollective/application/echo.rb_, the one below is a simple application that speaks to a hypothetical _echo_ action of a _helloworld_ agent. This agent has been demonstrated in : writing [agents][SimpleRPCAgents].
85 class MCollective::Application::Echo<MCollective::Application
86 description "Reports on usage for a specific fact"
89 :description => "Message to send",
90 :arguments => ["-m", "--message MESSAGE"],
95 mc = rpcclient("helloworld")
97 printrpc mc.echo(:msg => configuration[:message], :options => options)
104 Here's the application we wrote in action:
106 {% highlight console %}
108 The message option is mandatory
110 Please run with --help for detailed help
113 {% highlight console %}
116 * [ ============================================================> ] 1 / 1
121 Time: Mon Jan 31 21:27:03 +0000 2011
124 Finished processing 1 / 1 hosts in 68.53 ms
127 Most of the techniques documented in SimpleRPC [Clients] can be reused here, we've just simplified a lot of the common used patterns like CLI arguments and incorporated it all in a single framework.
133 To add custom usage messages to your application we can add lines like this:
136 class MCollective::Application::Echo<MCollective::Application
137 description "Reports on usage for a specific fact"
139 usage "mco echo [options] --message message"
143 You can add several of these messages by just adding multiple such lines.
145 ### Application Options
147 A standard options hash is available simply as options you can manipulate it and pass it into the RPC Client like normal. See the SimpleRPC [Clients] reference for more on this.
149 ### CLI Argument Parsing
151 There are several options available to assist in parsing CLI arguments. The most basic option is:
154 class MCollective::Application::Echo<MCollective::Application
156 :description => "Message to send",
157 :arguments => ["-m", "--message MESSAGE"]
161 In this case if the user used either _-m message_ or _--message message_ on the CLI the desired message would be in _configuration`[`:message`]`_
163 #### Required Arguments
164 You can require that a certain parameter is always passed:
168 :description => "Message to send",
169 :arguments => ["-m", "--message MESSAGE"],
173 #### Argument data types
174 CLI arguments can be forced to a specific type, we also have some additional special types that the default ruby option parser cant handle on its own.
176 You can force data to be of type String, Fixnum etc:
180 :description => "Count",
181 :arguments => ["--count MESSAGE"],
185 You can force an argument to be boolean:
189 :description => "Detailed view",
190 :arguments => ["--detail"],
194 If you have an argument that can be called many times you can force that to build an array:
198 :description => "Arguments",
199 :arguments => ["--argument ARG"],
203 Here if you supplied multiple arguments _configuration`[`:args`]`_ will be an array with all the options supplied.
205 #### Argument validation
206 You can validate input passed on the CLI:
210 :description => "Count",
211 :arguments => ["--count MESSAGE"],
213 :validate => Proc.new {|val| val < 10 ? true : "The message count has to be below 10" }
216 Should the supplied value be 10 or more a error message will be displayed.
218 #### Disabling standard sections of arguments
219 By default every Application get all the RPC options enabling filtering, discovery etc. In some cases this is undesirable so we let users disable those.
222 class MCollective::Application::Echo<MCollective::Application
223 exclude_argument_sections "common", "filter", "rpc"
227 This application will only have --help, --verbose and --config as options, all the other options will be removed.
229 #### Post argument parsing hook
230 Right after all arguments are parsed you can have a hook in your program called, this hook could perhaps parse the remaining data on _ARGV_ after option parsing is complete.
233 class MCollective::Application::Echo<MCollective::Application
234 description "Reports on usage for a specific fact"
236 def post_option_parser(configuration)
238 configuration[:message] = ARGV.shift
240 STDERR.puts "Please specify a message on the command line"
246 # use configuration[:message] here to access the message
251 #### Validating configuration
252 After the options are parsed and the post hook is called you can validate the contents of the configuration:
255 class MCollective::Application::Echo<MCollective::Application
256 description "Reports on usage for a specific fact"
258 # parse the first argument as a message
259 def post_option_parser(configuration)
260 configuration[:message] = ARGV.shift unless ARGV.empty?
263 # stop the application if we didnt receive a message
264 def validate_configuration(configuration)
265 raise "Need to supply a message on the command line" unless configuration.include?(:message)
269 # use configuration[:message] here to access the message
274 ### Exiting your application
275 You can use the normal _exit_ Ruby method at any time to exit your application and you can supply any
278 The supplied applications have a standard exit code convention, if you want your applications to exhibit
279 the same behavior use the _halt_ helper. The exit codes are below:
282 |----|-----------------------------------------------------|
283 |0 |Nodes were discovered and all passed |
284 |0 |No discovery was done but responses were received |
285 |1 |No nodes were discovered |
286 |2 |Nodes were discovered but some responses failed |
287 |3 |Nodes were discovered but no responses were received |
288 |4 |No discovery were done and no responses were received|
291 class MCollective::Application::Echo<MCollective::Application
292 description "Reports on usage for a specific fact"
295 mc = rpcclient("echo")
297 printrpc mc.echo(:msg => "Hello World", :options => options)
306 As you can see you pass the _halt_ helper an instance of the RPC Client statistics and it will then
307 use that to do the right exit code.