+require 'pp'
+
+module MCollective
+ # Toolset to create a standard interface of client and agent using
+ # an RPC metaphor, standard compliant agents will make it easier
+ # to create generic clients like web interfaces etc
+ module RPC
+ autoload :ActionRunner, "mcollective/rpc/actionrunner"
+ autoload :Agent, "mcollective/rpc/agent"
+ autoload :Audit, "mcollective/rpc/audit"
+ autoload :Client, "mcollective/rpc/client"
+ autoload :Helpers, "mcollective/rpc/helpers"
+ autoload :Progress, "mcollective/rpc/progress"
+ autoload :Reply, "mcollective/rpc/reply"
+ autoload :Request, "mcollective/rpc/request"
+ autoload :Result, "mcollective/rpc/result"
+ autoload :Stats, "mcollective/rpc/stats"
+
+ # Creates a standard options hash, pass in a block to add extra headings etc
+ # see Optionparser
+ def rpcoptions
+ oparser = MCollective::Optionparser.new({:verbose => false, :progress_bar => true}, "filter")
+
+ options = oparser.parse do |parser, options|
+ if block_given?
+ yield(parser, options)
+ end
+
+ Helpers.add_simplerpc_options(parser, options)
+ end
+
+ return options
+ end
+
+ # Wrapper to create clients, supposed to be used as
+ # a mixin:
+ #
+ # include MCollective::RPC
+ #
+ # exim = rpcclient("exim")
+ # printrpc exim.mailq
+ #
+ # or
+ #
+ # rpcclient("exim") do |exim|
+ # printrpc exim.mailq
+ # end
+ #
+ # It will take a few flags:
+ # :configfile => "etc/client.cfg"
+ # :options => options
+ # :exit_on_failure => true
+ #
+ # Options would be a build up options hash from the Optionparser
+ # you can use the rpcoptions helper to create this
+ #
+ # :exit_on_failure is true by default, and causes the application to
+ # exit if there is a failure constructing the RPC client. Set this flag
+ # to false to cause an Exception to be raised instead.
+ def rpcclient(agent, flags = {})
+ configfile = flags[:configfile] || "/etc/mcollective/client.cfg"
+ options = flags[:options] || nil
+
+ if flags.key?(:exit_on_failure)
+ exit_on_failure = flags[:exit_on_failure]
+ else
+ # We exit on failure by default for CLI-friendliness
+ exit_on_failure = true
+ end
+
+ begin
+ if options
+ rpc = Client.new(agent, :configfile => options[:config], :options => options)
+ @options = rpc.options
+ else
+ rpc = Client.new(agent, :configfile => configfile)
+ @options = rpc.options
+ end
+ rescue Exception => e
+ if exit_on_failure
+ puts("Could not create RPC client: #{e}")
+ exit!
+ else
+ raise e
+ end
+ end
+
+ if block_given?
+ yield(rpc)
+ else
+ return rpc
+ end
+ end
+
+ # means for other classes to drop stats into this module
+ # its a bit hacky but needed so that the mixin methods like
+ # printrpcstats can easily get access to it without
+ # users having to pass it around in params.
+ def self.stats(stats)
+ @@stats = stats
+ end
+
+ # means for other classes to drop discovered hosts into this module
+ # its a bit hacky but needed so that the mixin methods like
+ # printrpcstats can easily get access to it without
+ # users having to pass it around in params.
+ def self.discovered(discovered)
+ @@discovered = discovered
+ end
+
+ # Prints stats, requires stats to be saved from elsewhere
+ # using the MCollective::RPC.stats method.
+ #
+ # If you've passed -v on the command line a detailed stat block
+ # will be printed, else just a one liner.
+ #
+ # You can pass flags into it:
+ #
+ # printrpcstats :caption => "Foo", :summarize => true
+ #
+ # This will use "Foo" as the caption to the stats in verbose
+ # mode and print out any aggregate summary information if present
+ def printrpcstats(flags={})
+ return unless @options[:output_format] == :console
+
+ flags = {:summarize => false, :caption => "rpc stats"}.merge(flags)
+
+ verbose = @options[:verbose] rescue verbose = false
+
+ begin
+ stats = @@stats
+ rescue
+ puts("no stats to display")
+ return
+ end
+
+ puts stats.report(flags[:caption], flags[:summarize], verbose)
+ end
+
+ # Prints the result of an RPC call.
+ #
+ # In the default quiet mode - no flattening or verbose - only results
+ # that produce an error will be printed
+ #
+ # To get details of each result run with the -v command line option.
+ def printrpc(result, flags = {})
+ verbose = @options[:verbose] rescue verbose = false
+ verbose = flags[:verbose] || verbose
+ flatten = flags[:flatten] || false
+ format = @options[:output_format]
+ forced_mode = @options[:force_display_mode] || false
+
+ result_text = Helpers.rpcresults(result, {:verbose => verbose, :flatten => flatten, :format => format, :force_display_mode => forced_mode})
+
+ if result.is_a?(Array) && format == :console
+ puts "\n%s\n" % [ result_text ]
+ else
+ # when we get just one result to print dont pad them all with
+ # blank spaces etc, just print the individual result with no
+ # padding
+ puts result_text unless result_text == ""
+ end
+ end
+
+ # Wrapper for MCollective::Util.empty_filter? to make clients less fugly
+ # to write - ticket #18
+ def empty_filter?(options)
+ if options.include?(:filter)
+ Util.empty_filter?(options[:filter])
+ else
+ Util.empty_filter?(options)
+ end
+ end
+
+ def self.const_missing(const_name)
+ super unless const_name == :DDL
+
+ Log.warn("MCollective::RPC::DDL is deprecatd, please use MCollective::DDL instead")
+ MCollective::DDL
+ end
+ end
+end