575d069b1f1bd7087e5e46bb52b210c8bdaeb41c
[packages/precise/mcollective.git] / lib / mcollective / rpc.rb
1 require 'pp'
2
3 module MCollective
4   # Toolset to create a standard interface of client and agent using
5   # an RPC metaphor, standard compliant agents will make it easier
6   # to create generic clients like web interfaces etc
7   module RPC
8     autoload :ActionRunner, "mcollective/rpc/actionrunner"
9     autoload :Agent, "mcollective/rpc/agent"
10     autoload :Audit, "mcollective/rpc/audit"
11     autoload :Client, "mcollective/rpc/client"
12     autoload :Helpers, "mcollective/rpc/helpers"
13     autoload :Progress, "mcollective/rpc/progress"
14     autoload :Reply, "mcollective/rpc/reply"
15     autoload :Request, "mcollective/rpc/request"
16     autoload :Result, "mcollective/rpc/result"
17     autoload :Stats, "mcollective/rpc/stats"
18
19     # Creates a standard options hash, pass in a block to add extra headings etc
20     # see Optionparser
21     def rpcoptions
22       oparser = MCollective::Optionparser.new({:verbose => false, :progress_bar => true}, "filter")
23
24       options = oparser.parse do |parser, options|
25         if block_given?
26           yield(parser, options)
27         end
28
29         Helpers.add_simplerpc_options(parser, options)
30       end
31
32       return options
33     end
34
35     # Wrapper to create clients, supposed to be used as
36     # a mixin:
37     #
38     # include MCollective::RPC
39     #
40     # exim = rpcclient("exim")
41     # printrpc exim.mailq
42     #
43     # or
44     #
45     # rpcclient("exim") do |exim|
46     #    printrpc exim.mailq
47     # end
48     #
49     # It will take a few flags:
50     #    :configfile => "etc/client.cfg"
51     #    :options => options
52     #    :exit_on_failure => true
53     #
54     # Options would be a build up options hash from the Optionparser
55     # you can use the rpcoptions helper to create this
56     #
57     # :exit_on_failure is true by default, and causes the application to
58     # exit if there is a failure constructing the RPC client. Set this flag
59     # to false to cause an Exception to be raised instead.
60     def rpcclient(agent, flags = {})
61       configfile = flags[:configfile] || "/etc/mcollective/client.cfg"
62       options = flags[:options] || nil
63
64       if flags.key?(:exit_on_failure)
65         exit_on_failure = flags[:exit_on_failure]
66       else
67         # We exit on failure by default for CLI-friendliness
68         exit_on_failure = true
69       end
70
71       begin
72         if options
73           rpc = Client.new(agent, :configfile => options[:config], :options => options)
74           @options = rpc.options
75         else
76           rpc = Client.new(agent, :configfile => configfile)
77           @options = rpc.options
78         end
79       rescue Exception => e
80         if exit_on_failure
81           puts("Could not create RPC client: #{e}")
82           exit!
83         else
84           raise e
85         end
86       end
87
88       if block_given?
89         yield(rpc)
90       else
91         return rpc
92       end
93     end
94
95     # means for other classes to drop stats into this module
96     # its a bit hacky but needed so that the mixin methods like
97     # printrpcstats can easily get access to it without
98     # users having to pass it around in params.
99     def self.stats(stats)
100       @@stats = stats
101     end
102
103     # means for other classes to drop discovered hosts into this module
104     # its a bit hacky but needed so that the mixin methods like
105     # printrpcstats can easily get access to it without
106     # users having to pass it around in params.
107     def self.discovered(discovered)
108       @@discovered = discovered
109     end
110
111     # Prints stats, requires stats to be saved from elsewhere
112     # using the MCollective::RPC.stats method.
113     #
114     # If you've passed -v on the command line a detailed stat block
115     # will be printed, else just a one liner.
116     #
117     # You can pass flags into it:
118     #
119     #   printrpcstats :caption => "Foo", :summarize => true
120     #
121     # This will use "Foo" as the caption to the stats in verbose
122     # mode and print out any aggregate summary information if present
123     def printrpcstats(flags={})
124       return unless @options[:output_format] == :console
125
126       flags = {:summarize => false, :caption => "rpc stats"}.merge(flags)
127
128       verbose = @options[:verbose] rescue verbose = false
129
130       begin
131         stats = @@stats
132       rescue
133         puts("no stats to display")
134         return
135       end
136
137       puts stats.report(flags[:caption], flags[:summarize], verbose)
138     end
139
140     # Prints the result of an RPC call.
141     #
142     # In the default quiet mode - no flattening or verbose - only results
143     # that produce an error will be printed
144     #
145     # To get details of each result run with the -v command line option.
146     def printrpc(result, flags = {})
147       verbose = @options[:verbose] rescue verbose = false
148       verbose = flags[:verbose] || verbose
149       flatten = flags[:flatten] || false
150       format = @options[:output_format]
151       forced_mode = @options[:force_display_mode] || false
152
153       result_text =  Helpers.rpcresults(result, {:verbose => verbose, :flatten => flatten, :format => format, :force_display_mode => forced_mode})
154
155       if result.is_a?(Array) && format == :console
156         puts "\n%s\n" % [ result_text ]
157       else
158         # when we get just one result to print dont pad them all with
159         # blank spaces etc, just print the individual result with no
160         # padding
161         puts result_text unless result_text == ""
162       end
163     end
164
165     # Wrapper for MCollective::Util.empty_filter? to make clients less fugly
166     # to write - ticket #18
167     def empty_filter?(options)
168       if options.include?(:filter)
169         Util.empty_filter?(options[:filter])
170       else
171         Util.empty_filter?(options)
172       end
173     end
174
175     def self.const_missing(const_name)
176       super unless const_name == :DDL
177
178       Log.warn("MCollective::RPC::DDL is deprecatd, please use MCollective::DDL instead")
179       MCollective::DDL
180     end
181   end
182 end