X-Git-Url: https://review.fuel-infra.org/gitweb?a=blobdiff_plain;f=website%2Freference%2Fplugins%2Faggregate.md;fp=website%2Freference%2Fplugins%2Faggregate.md;h=3fca4d16755bcd33ca0d0cf187f5eb04cf304417;hb=b87d2f4e68281062df1913440ca5753ae63314a9;hp=0000000000000000000000000000000000000000;hpb=ab0ea530b8ac956091f17b104ab2311336cfc250;p=packages%2Fprecise%2Fmcollective.git diff --git a/website/reference/plugins/aggregate.md b/website/reference/plugins/aggregate.md new file mode 100644 index 0000000..3fca4d1 --- /dev/null +++ b/website/reference/plugins/aggregate.md @@ -0,0 +1,369 @@ +--- +layout: default +title: Aggregate Plugins +--- +[DDL]: /mcollective/reference/plugins/ddl.html +[Examples]: https://github.com/puppetlabs/marionette-collective/tree/master/plugins/mcollective/aggregate + +## Overview +MCollective Agents return data and we try to provide as much usable user +interface for free. To aid in this we require agents to have [DDL] files that +describe the data that the agent returns. + +DDL files are used to configure the client but also to assist with user +interface generation. They are used to ask questions that an action needs but +also to render the results when the replies come in. For example we turn +*:freecpu* into "Free CPU" when displaying the data based on the DDL. + +Previously if data that agents returned required any summarization this had to +be done using a custom application. Here is an example from *mco nrpe*: + +{% highlight console %} +% mco nrpe check_load +. +. +Finished processing 25 / 25 hosts in 556.48 ms + + OK: 25 + WARNING: 0 + CRITICAL: 0 + UNKNOWN: 0 +{% endhighlight %} + +Here to get the summary of results displayed in a way that has contextual +relevance to the nrpe plugin a custom application had to be written and anyone +who interacts with the agent using other RPC clients would not get the benefit +of this summary. + +By using aggregate plugins and updating the DDL we can now provide such a +summary in all result sets and display it using the *mco rpc* application and +any calls to *printrpc*. + +{% highlight console %} +% mco rpc nrpe runcommand command=check_load +Discovering hosts using the mongo method .... 25 + + * [============================================================> ] 25 / 25 + +Summary of Exit Code: + + OK : 25 + WARNING : 0 + UNKNOWN : 0 + CRITICAL : 0 + + +Finished processing 25 / 25 hosts in 390.70 ms +{% endhighlight %} + +Here you get a similar summary as before, all that had to be done was a simple +aggregate plugin be written and distributed with your clients. + +The results are shown as above using *printrpcstats* but you can also get access to +the raw data so you can decide to render it in some other way - perhaps using a +graph on a web interface. + +We provide a number of aggregate plugins with MCollective and anyone can write +more. + +For examples that already use functions see the *rpcutil* agent - its +*collective_info*, *get_fact*, *daemon_stats* and *get_config_item* actions all +have summaries applied. + +*NOTE:* This feature is available since version 2.1.0 + +## Using existing plugins + +### Updating the DDL +At present MCollective supplies 3 plugins *average()*, *summary()* and *sum()* +you can use these in any agent, here is an example from the *rpcutil* agent DDL +file: + +{% highlight ruby %} +action "get_config_item", :description => "Get the active value of a specific config property" do + output :value, + :description => "The value that is in use", + :display_as => "Value" + + summarize do + aggregate summary(:value) + end +end +{% endhighlight %} + +We've removed a few lines from this example DDL block leaving only the relevant +lines. You can see the agent outputs data called *:value* and we reference that +output in the summary function *summary(:value)*, the result would look like +this: + +### Viewing summaries on the CLI +{% highlight console %} +% mco rpc rpcutil get_config_item item=collectives +. +. +dev8 + Property: collectives + Value: ["mcollective", "uk_collective"] + +Summary of Value: + + mcollective = 25 + uk_collective = 15 + fr_collective = 9 + us_collective = 1 + +Finished processing 25 / 25 hosts in 349.70 ms +{% endhighlight %} + +You can see that the value in this case contains arrays, the *summary()* +function produce the table in the output showing the data distribution. + +### Producing summaries in your own clients +You can enable the same display in your own code, here is ruby code that has the +same affect as the CLI call above: + +{% highlight ruby %} +require 'mcollective' + +include MCollective::RPC + +c = rpcclient("rpcutil") + +printrpc c.get_config_item(:item => "collectives") + +printrpcstats :summarize => true +{% endhighlight %} + +Without passing in the *:summarize => true* you would not see the summaries + +### Getting access to the raw summary results +If you wanted to do something else entirely like produce a graph on a web page +of the summaries you can get access to the raw data, here's some ruby code to +show all computed summaries: + +{% highlight ruby %} +require 'mcollective' + +include MCollective::RPC + +c = rpcclient("rpcutil") +c.progress = false + +c.get_config_item(:item => "collectives") + +c.stats.aggregate_summary.each do |summary| + puts "Summary of type: %s" % summary.result_type + puts "Display format: '%s'" % summary.aggregate_format + puts + pp summary.result +end +{% endhighlight %} + +As you can see you will get an array of summaries this is because each DDL can +use many aggregate calls, this would be an array of all the computed summaries: + +{% highlight console %} +Summary of type: collection +Display format: '%13s = %s' + +{:type=>:collection, + :value=> + {"mcollective"=>25, + "fr_collective"=>9, + "us_collective"=>1, + "uk_collective"=>15}, + :output=>:value} +{% endhighlight %} + +There are 2 types of result *:collection* and *:numeric*, in the case of numeric +results the :value would just be a number. + +The *aggregate_format* is either a user supplied format or a dynamically +computed format to display the summary results on the console. In this case +each pair of the hash should be displayed using the format to produce a nice +right justified list of keys and values. + +## Writing your own function +We'll cover writing your own function by looking at the Nagios one from earlier +in this example. You can look at [the functions supplied with +MCollective][Examples] for more examples using other types than the one below. + +First lets look at the DDL for the existing *nrpe* Agent: + +{% highlight ruby %} +action "runcommand", :description => "Run a NRPE command" do + input :command, + :prompt => "Command", + :description => "NRPE command to run", + :type => :string, + :validation => '\A[a-zA-Z0-9_-]+\z', + :optional => false, + :maxlength => 50 + + output :output, + :description => "Output from the Nagios plugin", + :display_as => "Output", + :default => "" + + output :exitcode, + :description => "Exit Code from the Nagios plugin", + :display_as => "Exit Code", + :default => 3 + + output :perfdata, + :description => "Performance Data from the Nagios plugin", + :display_as => "Performance Data", + :default => "" +end +{% endhighlight %} + +You can see it will return an *:exitcode* item and from the default value you +can gather this is going to be a number. Nagios defines 4 possibly exit codes +for a Nagios plugin and we need to convert this *:exitcode* into a string like +WARNING, CRITICAL, UNKNOWN or OK. + +Usually when writing any kind of summarizer for an array of results your code +might contain 3 phases. + +Given a series of Nagios results like this: + +{% highlight ruby %} +[ + {:exitcode => 0, :output => "OK", :perfdata => ""}, + {:exitcode => 2, :output => "failure", :perfdata => ""} +] +{% endhighlight %} + +You would write a nagios_states() function that does roughly this: + +{% highlight ruby %} +def nagios_states(results) + # set initial values + result = {} + status_map = ["OK", "WARNING", "CRITICAL", "UNKNOWN"] + status_map.each {|s| result[s] = 0} + + # loop over all the data, increment the count for OK etc + results.each do |result| + status = status_map[result[:exitcode]] + result[status] += 1 + end + + # return the result hash, {"OK" => 1, "CRITICAL" => 1, "WARN" => 0, "UNKNOWN" => 0} + return result +end +{% endhighlight %} + +You could optimise the code but you can see there are 3 major stages in the life +of this code. + + * Set initial values for the return data + * Loop the data building up the state + * Return the data. + +Given this, here is our Nagios exitcode summary function, it is roughly the same +code with a bit more boiler plate to plugin into mcollective, but the same code +can be seen: + +{% highlight ruby %} +module MCollective + class Aggregate + class Nagios_states "Run a NRPE command" do + . + . + . + + if respond_to?(:summarize) + summarize do + aggregate nagios_states(:exitcode) + end + end +end +{% endhighlight %} + +Add the last few lines - we check that we're running in a version of MCollective +that supports this feature and then we call our function with the *:exitcode* +results. + +