Class | MCollective::Application |
In: |
lib/mcollective/application.rb
|
Parent: | Object |
Sets the application description, there can be only one description per application so multiple calls will just change the description
# File lib/mcollective/application.rb, line 28 28: def description(descr) 29: self[:description] = descr 30: end
# 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
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]
# 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
Returns an array of all the arguments built using calls to optin
# File lib/mcollective/application.rb, line 245 245: def application_cli_arguments 246: application_options[:cli_arguments] 247: end
Retrieve the current application description
# File lib/mcollective/application.rb, line 232 232: def application_description 233: application_options[:description] 234: end
Handles failure, if we‘re far enough in the initialization phase it will log backtraces if its in verbose mode only
# File lib/mcollective/application.rb, line 251 251: def application_failure(e, err_dest=STDERR) 252: # peole can use exit() anywhere and not get nasty backtraces as a result 253: if e.is_a?(SystemExit) 254: disconnect 255: raise(e) 256: end 257: 258: err_dest.puts "\nThe %s application failed to run, use -v for full error details: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)] 259: 260: if options.nil? || options[:verbose] 261: e.backtrace.first << Util.colorize(:red, " <----") 262: err_dest.puts "\n%s %s" % [ Util.colorize(:red, e.to_s), Util.colorize(:bold, "(#{e.class.to_s})")] 263: e.backtrace.each{|l| err_dest.puts "\tfrom #{l}"} 264: end 265: 266: disconnect 267: 268: exit 1 269: end
Builds an ObjectParser config, parse the CLI options and validates based on the option config
# 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.define_tail "" 153: parser.define_tail "The Marionette Collective #{MCollective.version}" 154: 155: 156: application_cli_arguments.each do |carg| 157: opts_array = [] 158: 159: opts_array << :on 160: 161: # if a default is set from the application set it up front 162: if carg.include?(:default) 163: configuration[carg[:name]] = carg[:default] 164: end 165: 166: # :arguments are multiple possible ones 167: if carg[:arguments].is_a?(Array) 168: carg[:arguments].each {|a| opts_array << a} 169: else 170: opts_array << carg[:arguments] 171: end 172: 173: # type was given and its not one of our special types, just pass it onto optparse 174: opts_array << carg[:type] if carg[:type] && ![:boolean, :bool, :array].include?(carg[:type]) 175: 176: opts_array << carg[:description] 177: 178: # Handle our special types else just rely on the optparser to handle the types 179: if [:bool, :boolean].include?(carg[:type]) 180: parser.send(*opts_array) do |v| 181: validate_option(carg[:validate], carg[:name], v) 182: 183: configuration[carg[:name]] = true 184: end 185: 186: elsif carg[:type] == :array 187: parser.send(*opts_array) do |v| 188: validate_option(carg[:validate], carg[:name], v) 189: 190: configuration[carg[:name]] = [] unless configuration.include?(carg[:name]) 191: configuration[carg[:name]] << v 192: end 193: 194: else 195: parser.send(*opts_array) do |v| 196: validate_option(carg[:validate], carg[:name], v) 197: 198: configuration[carg[:name]] = v 199: end 200: end 201: end 202: end 203: end
Creates a standard options hash, pass in a block to add extra headings etc see Optionparser
# 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
# File lib/mcollective/application.rb, line 88 88: def configuration 89: @application_configuration ||= {} 90: @application_configuration 91: end
# File lib/mcollective/application.rb, line 293 293: def disconnect 294: MCollective::PluginManager["connector_plugin"].disconnect 295: rescue 296: 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 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 not responses received Exit with 4 if no discovery were done and no responses were received
# File lib/mcollective/application.rb, line 314 314: def halt(stats) 315: request_stats = {:discoverytime => 0, 316: :discovered => 0, 317: :failcount => 0}.merge(stats.to_hash) 318: 319: # was discovery done? 320: if request_stats[:discoverytime] != 0 321: # was any nodes discovered 322: if request_stats[:discovered] == 0 323: exit 1 324: 325: # nodes were discovered, did we get responses 326: elsif request_stats[:responses] == 0 327: exit 3 328: 329: else 330: # we got responses and discovery was done, no failures 331: if request_stats[:failcount] == 0 332: exit 0 333: else 334: exit 2 335: end 336: end 337: else 338: # discovery wasnt done and we got no responses 339: if request_stats[:responses] == 0 340: exit 4 341: else 342: exit 0 343: end 344: end 345: end
# File lib/mcollective/application.rb, line 271 271: def help 272: application_parse_options(true) 273: end
The active options hash used for MC::Client and other configuration
# 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
# File lib/mcollective/application.rb, line 350 350: def rpcclient(agent, flags = {}) 351: flags[:options] = options unless flags.include?(:options) 352: flags[:exit_on_failure] = false 353: 354: super 355: 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
# File lib/mcollective/application.rb, line 278 278: def run 279: application_parse_options 280: 281: validate_configuration(configuration) if respond_to?(:validate_configuration) 282: 283: Util.setup_windows_sleeper if Util.windows? 284: 285: main 286: 287: disconnect 288: 289: rescue Exception => e 290: application_failure(e) 291: end
# File lib/mcollective/application.rb, line 205 205: def validate_cli_options 206: # Check all required parameters were set 207: validation_passed = true 208: application_cli_arguments.each do |carg| 209: # Check for required arguments 210: if carg[:required] 211: unless configuration[ carg[:name] ] 212: validation_passed = false 213: STDERR.puts "The #{carg[:name]} option is mandatory" 214: end 215: end 216: end 217: 218: unless validation_passed 219: STDERR.puts "\nPlease run with --help for detailed help" 220: exit 1 221: end 222: 223: 224: end
Calls the supplied block in an option for validation, an error raised will log to STDERR and exit the application
# 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