Class MCollective::Application
In: lib/mcollective/application.rb
Parent: Object

Methods

Included Modules

RPC

Public Class methods

retrieves a specific option

[Source]

    # File lib/mcollective/application.rb, line 20
20:       def [](option)
21:         intialize_application_options unless @application_options
22:         @application_options[option]
23:       end

set an option in the options hash

[Source]

    # File lib/mcollective/application.rb, line 14
14:       def []=(option, value)
15:         intialize_application_options unless @application_options
16:         @application_options[option] = value
17:       end

Intialize a blank set of options if its the first time used else returns active options

[Source]

    # File lib/mcollective/application.rb, line 8
 8:       def application_options
 9:         intialize_application_options unless @application_options
10:         @application_options
11:       end

Sets the application description, there can be only one description per application so multiple calls will just change the description

[Source]

    # File lib/mcollective/application.rb, line 28
28:       def description(descr)
29:         self[:description] = descr
30:       end

[Source]

    # File lib/mcollective/application.rb, line 38
38:       def exclude_argument_sections(*sections)
39:         sections = [sections].flatten
40: 
41:         sections.each do |s|
42:           raise "Unknown CLI argument section #{s}" unless ["rpc", "common", "filter"].include?(s)
43:         end
44: 
45:         intialize_application_options unless @application_options
46:         self[:exclude_arg_sections] = sections
47:       end

Creates an empty set of options

[Source]

    # File lib/mcollective/application.rb, line 79
79:       def intialize_application_options
80:         @application_options = {:description          => nil,
81:                                 :usage                => [],
82:                                 :cli_arguments        => [],
83:                                 :exclude_arg_sections => []}
84:       end

Wrapper to create command line options

 - name: varaible name that will be used to access the option value
 - description: textual info shown in --help
 - arguments: a list of possible arguments that can be used
   to activate this option
 - type: a data type that ObjectParser understand of :bool or :array
 - required: true or false if this option has to be supplied
 - validate: a proc that will be called with the value used to validate
   the supplied value

  option :foo,
         :description => "The foo option"
         :arguments   => ["--foo ARG"]

after this the value supplied will be in configuration[:foo]

[Source]

    # File lib/mcollective/application.rb, line 65
65:       def option(name, arguments)
66:         opt = {:name => name,
67:                :description => nil,
68:                :arguments => [],
69:                :type => String,
70:                :required => false,
71:                :validate => Proc.new { true }}
72: 
73:         arguments.each_pair{|k,v| opt[k] = v}
74: 
75:         self[:cli_arguments] << opt
76:       end

Supplies usage information, calling multiple times will create multiple usage lines in —help output

[Source]

    # File lib/mcollective/application.rb, line 34
34:       def usage(usage)
35:         self[:usage] << usage
36:       end

Public Instance methods

Returns an array of all the arguments built using calls to optin

[Source]

     # File lib/mcollective/application.rb, line 247
247:     def application_cli_arguments
248:       application_options[:cli_arguments]
249:     end

Retrieve the current application description

[Source]

     # File lib/mcollective/application.rb, line 234
234:     def application_description
235:       application_options[:description]
236:     end

Handles failure, if we‘re far enough in the initialization phase it will log backtraces if its in verbose mode only

[Source]

     # File lib/mcollective/application.rb, line 253
253:     def application_failure(e, err_dest=STDERR)
254:       # peole can use exit() anywhere and not get nasty backtraces as a result
255:       if e.is_a?(SystemExit)
256:         disconnect
257:         raise(e)
258:       end
259: 
260:       if e.is_a?(CodedError)
261:         err_dest.puts "\nThe %s application failed to run: %s: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:bold, e.code), Util.colorize(:red, e.to_s)]
262: 
263:         err_dest.puts
264:         if options[:verbose]
265:           err_dest.puts "Use the 'mco doc %s' command for details about this error" % e.code
266:         else
267:           err_dest.puts "Use the 'mco doc %s' command for details about this error, use -v for full error backtrace details" % e.code
268:         end
269:       else
270:         if options[:verbose]
271:           err_dest.puts "\nThe %s application failed to run: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)]
272:         else
273:           err_dest.puts "\nThe %s application failed to run, use -v for full error backtrace details: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)]
274:         end
275:       end
276: 
277:       if options.nil? || options[:verbose]
278:         e.backtrace.first << Util.colorize(:red, "  <----")
279:         err_dest.puts "\n%s %s" % [ Util.colorize(:red, e.to_s), Util.colorize(:bold, "(#{e.class.to_s})")]
280:         e.backtrace.each{|l| err_dest.puts "\tfrom #{l}"}
281:       end
282: 
283:       disconnect
284: 
285:       exit 1
286:     end

Retrieves the full hash of application options

[Source]

     # File lib/mcollective/application.rb, line 229
229:     def application_options
230:       self.class.application_options
231:     end

Builds an ObjectParser config, parse the CLI options and validates based on the option config

[Source]

     # File lib/mcollective/application.rb, line 135
135:     def application_parse_options(help=false)
136:       @options ||= {:verbose => false}
137: 
138:       @options = clioptions(help) do |parser, options|
139:         parser.define_head application_description if application_description
140:         parser.banner = ""
141: 
142:         if application_usage
143:           parser.separator ""
144: 
145:           application_usage.each do |u|
146:             parser.separator "Usage: #{u}"
147:           end
148: 
149:           parser.separator ""
150:         end
151: 
152:         parser.separator "Application Options" unless application_cli_arguments.empty?
153: 
154:         parser.define_tail ""
155:         parser.define_tail "The Marionette Collective #{MCollective.version}"
156: 
157: 
158:         application_cli_arguments.each do |carg|
159:           opts_array = []
160: 
161:           opts_array << :on
162: 
163:           # if a default is set from the application set it up front
164:           if carg.include?(:default)
165:             configuration[carg[:name]] = carg[:default]
166:           end
167: 
168:           # :arguments are multiple possible ones
169:           if carg[:arguments].is_a?(Array)
170:             carg[:arguments].each {|a| opts_array << a}
171:           else
172:             opts_array << carg[:arguments]
173:           end
174: 
175:           # type was given and its not one of our special types, just pass it onto optparse
176:           opts_array << carg[:type] if carg[:type] && ![:boolean, :bool, :array].include?(carg[:type])
177: 
178:           opts_array << carg[:description]
179: 
180:           # Handle our special types else just rely on the optparser to handle the types
181:           if [:bool, :boolean].include?(carg[:type])
182:             parser.send(*opts_array) do |v|
183:               validate_option(carg[:validate], carg[:name], v)
184: 
185:               configuration[carg[:name]] = v
186:             end
187: 
188:           elsif carg[:type] == :array
189:             parser.send(*opts_array) do |v|
190:               validate_option(carg[:validate], carg[:name], v)
191: 
192:               configuration[carg[:name]] = [] unless configuration.include?(carg[:name])
193:               configuration[carg[:name]] << v
194:             end
195: 
196:           else
197:             parser.send(*opts_array) do |v|
198:               validate_option(carg[:validate], carg[:name], v)
199: 
200:               configuration[carg[:name]] = v
201:             end
202:           end
203:         end
204:       end
205:     end

Return the current usage text false if nothing is set

[Source]

     # File lib/mcollective/application.rb, line 239
239:     def application_usage
240:       usage = application_options[:usage]
241: 
242:       usage.empty? ? false : usage
243:     end

Creates a standard options hash, pass in a block to add extra headings etc see Optionparser

[Source]

     # File lib/mcollective/application.rb, line 111
111:     def clioptions(help)
112:       oparser = Optionparser.new({:verbose => false, :progress_bar => true}, "filter", application_options[:exclude_arg_sections])
113: 
114:       options = oparser.parse do |parser, options|
115:         if block_given?
116:           yield(parser, options)
117:         end
118: 
119:         RPC::Helpers.add_simplerpc_options(parser, options) unless application_options[:exclude_arg_sections].include?("rpc")
120:       end
121: 
122:       return oparser.parser.help if help
123: 
124:       validate_cli_options
125: 
126:       post_option_parser(configuration) if respond_to?(:post_option_parser)
127: 
128:       return options
129:     rescue Exception => e
130:       application_failure(e)
131:     end

The application configuration built from CLI arguments

[Source]

    # File lib/mcollective/application.rb, line 88
88:     def configuration
89:       @application_configuration ||= {}
90:       @application_configuration
91:     end

[Source]

     # File lib/mcollective/application.rb, line 310
310:     def disconnect
311:       MCollective::PluginManager["connector_plugin"].disconnect
312:     rescue
313:     end

A helper that creates a consistent exit code for applications by looking at an instance of MCollective::RPC::Stats

Exit with 0 if nodes were discovered and all passed Exit with 0 if no discovery were done and > 0 responses were received, all ok Exit with 1 if no nodes were discovered Exit with 2 if nodes were discovered but some RPC requests failed Exit with 3 if nodes were discovered, but no responses received Exit with 4 if no discovery were done and no responses were received

[Source]

     # File lib/mcollective/application.rb, line 345
345:     def halt(stats)
346:       exit(halt_code(stats))
347:     end

[Source]

     # File lib/mcollective/application.rb, line 322
322:     def halt_code(stats)
323:       request_stats = {:discoverytime => 0,
324:                        :discovered => 0,
325:                        :okcount => 0,
326:                        :failcount => 0}.merge(stats.to_hash)
327: 
328:       return 4 if request_stats[:discoverytime] == 0 && request_stats[:responses] == 0
329:       return 3 if request_stats[:discovered] > 0 && request_stats[:responses] == 0
330:       return 2 if request_stats[:discovered] > 0 && request_stats[:failcount] > 0
331:       return 1 if request_stats[:discovered] == 0
332:       return 0 if request_stats[:discoverytime] == 0 && request_stats[:discovered] == request_stats[:okcount]
333:       return 0 if request_stats[:discovered] == request_stats[:okcount]
334:     end

[Source]

     # File lib/mcollective/application.rb, line 288
288:     def help
289:       application_parse_options(true)
290:     end

Fake abstract class that logs if the user tries to use an application without supplying a main override method.

[Source]

     # File lib/mcollective/application.rb, line 317
317:     def main
318:       STDERR.puts "Applications need to supply a 'main' method"
319:       exit 1
320:     end

The active options hash used for MC::Client and other configuration

[Source]

    # File lib/mcollective/application.rb, line 94
94:     def options
95:       @options
96:     end

Wrapper around MC::RPC#rpcclient that forcably supplies our options hash if someone forgets to pass in options in an application the filters and other cli options wouldnt take effect which could have a disasterous outcome

[Source]

     # File lib/mcollective/application.rb, line 352
352:     def rpcclient(agent, flags = {})
353:       flags[:options] = options unless flags.include?(:options)
354:       flags[:exit_on_failure] = false
355: 
356:       super
357:     end

The main logic loop, builds up the options, validate configuration and calls the main as supplied by the user. Disconnects when done and pass any exception onto the application_failure helper

[Source]

     # File lib/mcollective/application.rb, line 295
295:     def run
296:       application_parse_options
297: 
298:       validate_configuration(configuration) if respond_to?(:validate_configuration)
299: 
300:       Util.setup_windows_sleeper if Util.windows?
301: 
302:       main
303: 
304:       disconnect
305: 
306:     rescue Exception => e
307:       application_failure(e)
308:     end

[Source]

     # File lib/mcollective/application.rb, line 207
207:     def validate_cli_options
208:       # Check all required parameters were set
209:       validation_passed = true
210:       application_cli_arguments.each do |carg|
211:         # Check for required arguments
212:         if carg[:required]
213:           unless configuration[ carg[:name] ]
214:             validation_passed = false
215:             STDERR.puts "The #{carg[:name]} option is mandatory"
216:           end
217:         end
218:       end
219: 
220:       unless validation_passed
221:         STDERR.puts "\nPlease run with --help for detailed help"
222:         exit 1
223:       end
224: 
225: 
226:     end

Calls the supplied block in an option for validation, an error raised will log to STDERR and exit the application

[Source]

     # File lib/mcollective/application.rb, line 100
100:     def validate_option(blk, name, value)
101:       validation_result = blk.call(value)
102: 
103:       unless validation_result == true
104:         STDERR.puts "Validation of #{name} failed: #{validation_result}"
105:         exit 1
106:       end
107:     end

[Validate]