+++ /dev/null
----
-layout: default
-title: Single Executable Application Plugin
----
-[Clients]: ../../simplerpc/clients.html
-[SimpleRPCAgents]: ../../simplerpc/agents.html
-
-
-## Overview
-The Marionette Collective 1.1.1 and newer supports a single executable - called
-mco - and have a plugin type called application that lets you create
-applications for this single executable.
-
-In the past we tended to write small standalone scripts to interact with
-MCollective, this had a number of issues:
-
- * Large number of executables in _/usr/sbin_
- * Applications behave inconsistently with regard to error handling and reporting
- * Discovering new applications is difficult since they are all over the filesystem
- * Installation and packaging of plugins is complex
-
-We've attempted to address these concerns by creating a single point of access
-for all applications - the _mco_ script - with unified help, error reporting and
-option parsing.
-
-Below you can see the single executable system in use:
-
-{% highlight console %}
-The Marionette Collective version 2.0.0
-
-usage: /usr/bin/mco: command <options>
-
-Known commands:
-
- cap controller exim
- facts filemgr find
- help inventory iptables
- nettest nrpe package
- pgrep ping plugin
- puppetd rpc service
- virt
-
-Type 'mco help' for a detailed list of commands and 'mco help command'
-to get detailed help for a command
-
-{% endhighlight %}
-
-{% highlight console %}
-$ mco help
-The Marionette Collection version 2.0.0
-
- facts Reports on usage for a specific fact
- filemgr Generic File Manager Client
- find Find hosts matching criteria
- help Application list and RPC agent help
- inventory Shows an inventory for a given node
- ping Ping all nodes
- rpc Generic RPC agent client application
-{% endhighlight %}
-
-{% highlight console %}
-$ mco rpc package status package=zsh
-Determining the amount of hosts matching filter for 2 seconds .... 51
-
- * [ ============================================================> ] 51 / 51
-
-
- test.com:
- Properties:
- {:provider=>:yum,
- :release=>"3.el5",
- :arch=>"x86_64",
- :version=>"4.2.6",
- :epoch=>"0",
- :name=>"zsh",
- :ensure=>"4.2.6-3.el5"}
-{% endhighlight %}
-
-These applications are equivalent to the old mc-rpc and similar applications but without the problem of lots of files in _/usr/sbin_.
-
-## Basic Application
-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].
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- description "Reports on usage for a specific fact"
-
- option :message,
- :description => "Message to send",
- :arguments => ["-m", "--message MESSAGE"],
- :type => String,
- :required => true
-
- def main
- mc = rpcclient("helloworld")
-
- printrpc mc.echo(:msg => configuration[:message], :options => options)
-
- printrpcstats
- end
-end
-{% endhighlight %}
-
-Here's the application we wrote in action:
-
-{% highlight console %}
-$ mco echo
-The message option is mandatory
-
-Please run with --help for detailed help
-{% endhighlight %}
-
-{% highlight console %}
-$ mco echo -m test
-
- * [ ============================================================> ] 1 / 1
-
-
-example.com
- Message: test
- Time: Mon Jan 31 21:27:03 +0000 2011
-
-
-Finished processing 1 / 1 hosts in 68.53 ms
-{% endhighlight %}
-
-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.
-
-## Reference
-
-### Usage Messages
-
-To add custom usage messages to your application we can add lines like this:
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- description "Reports on usage for a specific fact"
-
- usage "mco echo [options] --message message"
-end
-{% endhighlight %}
-
-You can add several of these messages by just adding multiple such lines.
-
-### Application Options
-
-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.
-
-### CLI Argument Parsing
-
-There are several options available to assist in parsing CLI arguments. The most basic option is:
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- option :message,
- :description => "Message to send",
- :arguments => ["-m", "--message MESSAGE"]
-end
-{% endhighlight %}
-
-In this case if the user used either _-m message_ or _--message message_ on the CLI the desired message would be in _configuration`[`:message`]`_
-
-#### Required Arguments
-You can require that a certain parameter is always passed:
-
-{% highlight ruby %}
-option :message,
- :description => "Message to send",
- :arguments => ["-m", "--message MESSAGE"],
- :required => true
-{% endhighlight %}
-
-#### Argument data types
-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.
-
-You can force data to be of type String, Fixnum etc:
-
-{% highlight ruby %}
-option :count,
- :description => "Count",
- :arguments => ["--count MESSAGE"],
- :type => Fixnum
-{% endhighlight %}
-
-You can force an argument to be boolean:
-
-{% highlight ruby %}
-option :detail,
- :description => "Detailed view",
- :arguments => ["--detail"],
- :type => :bool
-{% endhighlight %}
-
-If you have an argument that can be called many times you can force that to build an array:
-
-{% highlight ruby %}
-option :args,
- :description => "Arguments",
- :arguments => ["--argument ARG"],
- :type => :array
-{% endhighlight %}
-
-Here if you supplied multiple arguments _configuration`[`:args`]`_ will be an array with all the options supplied.
-
-#### Argument validation
-You can validate input passed on the CLI:
-
-{% highlight ruby %}
-option :count,
- :description => "Count",
- :arguments => ["--count MESSAGE"],
- :type => Fixnum,
- :validate => Proc.new {|val| val < 10 ? true : "The message count has to be below 10" }
-{% endhighlight %}
-
-Should the supplied value be 10 or more a error message will be displayed.
-
-#### Disabling standard sections of arguments
-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.
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- exclude_argument_sections "common", "filter", "rpc"
-end
-{% endhighlight %}
-
-This application will only have --help, --verbose and --config as options, all the other options will be removed.
-
-#### Post argument parsing hook
-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.
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- description "Reports on usage for a specific fact"
-
- def post_option_parser(configuration)
- unless ARGV.empty?
- configuration[:message] = ARGV.shift
- else
- STDERR.puts "Please specify a message on the command line"
- exit 1
- end
- end
-
- def main
- # use configuration[:message] here to access the message
- end
-end
-{% endhighlight %}
-
-#### Validating configuration
-After the options are parsed and the post hook is called you can validate the contents of the configuration:
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- description "Reports on usage for a specific fact"
-
- # parse the first argument as a message
- def post_option_parser(configuration)
- configuration[:message] = ARGV.shift unless ARGV.empty?
- end
-
- # stop the application if we didnt receive a message
- def validate_configuration(configuration)
- raise "Need to supply a message on the command line" unless configuration.include?(:message)
- end
-
- def main
- # use configuration[:message] here to access the message
- end
-end
-{% endhighlight %}
-
-### Exiting your application
-You can use the normal _exit_ Ruby method at any time to exit your application and you can supply any
-exit code as normal.
-
-The supplied applications have a standard exit code convention, if you want your applications to exhibit
-the same behavior use the _halt_ helper. The exit codes are below:
-
-|Code|Description |
-|----|-----------------------------------------------------|
-|0 |Nodes were discovered and all passed |
-|0 |No discovery was done but responses were received |
-|1 |No nodes were discovered |
-|2 |Nodes were discovered but some responses failed |
-|3 |Nodes were discovered but no responses were received |
-|4 |No discovery were done and no responses were received|
-
-{% highlight ruby %}
-class MCollective::Application::Echo<MCollective::Application
- description "Reports on usage for a specific fact"
-
- def main
- mc = rpcclient("echo")
-
- printrpc mc.echo(:msg => "Hello World", :options => options)
-
- printrpcstats
-
- halt mc.stats
- end
-end
-{% endhighlight %}
-
-As you can see you pass the _halt_ helper an instance of the RPC Client statistics and it will then
-use that to do the right exit code.
-