Class: CommonCli
- Inherits:
-
Object
- Object
- CommonCli
- Defined in:
- lib/cli.rb
Overview
Implements what is shared between mssh and mcmd.
Instance Attribute Summary collapse
-
#command_to_target ⇒ Object
Returns the value of attribute command_to_target.
-
#extra_options ⇒ Object
writeonly
Sets the attribute extra_options.
-
#options ⇒ Object
Returns the value of attribute options.
-
#result ⇒ Object
Returns the value of attribute result.
-
#targets ⇒ Object
Returns the value of attribute targets.
Instance Method Summary collapse
-
#initialize(defaults) ⇒ CommonCli
constructor
A new instance of CommonCli.
- #output(result) ⇒ Object
-
#parse(argv) ⇒ Object
Parses a list of arguments, and yells at us if any are wrong.
- #runcmd ⇒ Object
Constructor Details
#initialize(defaults) ⇒ CommonCli
Returns a new instance of CommonCli.
11 12 13 14 |
# File 'lib/cli.rb', line 11 def initialize(defaults) @options = defaults @options[:hostname_token] = 'HOSTNAME' end |
Instance Attribute Details
#command_to_target ⇒ Object
Returns the value of attribute command_to_target.
8 9 10 |
# File 'lib/cli.rb', line 8 def command_to_target @command_to_target end |
#extra_options=(value) ⇒ Object (writeonly)
Sets the attribute extra_options
9 10 11 |
# File 'lib/cli.rb', line 9 def (value) @extra_options = value end |
#options ⇒ Object
Returns the value of attribute options.
8 9 10 |
# File 'lib/cli.rb', line 8 def @options end |
#result ⇒ Object
Returns the value of attribute result.
8 9 10 |
# File 'lib/cli.rb', line 8 def result @result end |
#targets ⇒ Object
Returns the value of attribute targets.
8 9 10 |
# File 'lib/cli.rb', line 8 def targets @targets end |
Instance Method Details
#output(result) ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/cli.rb', line 127 def output result ## Print as JSON array if (@options[:json_out]) require 'json' puts JSON.generate(result) return end # Concat stdout / stderr -> :all_buf result.each do |r| r[:all_buf] = "" r[:all_buf] += r[:stdout_buf].chomp if(!r[:stdout_buf].nil?) r[:all_buf] += r[:stderr_buf].chomp if(!r[:stderr_buf].nil?) end ## Collapse similar results if @options[:collapse] stdout_matches_success = Hash.new stdout_matches_failure = Hash.new result.each do |r| if r[:retval].success? stdout_matches_success[r[:all_buf]] = [] if stdout_matches_success[r[:all_buf]].nil? stdout_matches_success[r[:all_buf]] << @command_to_target[r[:command].object_id] else stdout_matches_failure[r[:all_buf]] = [] if stdout_matches_failure[r[:all_buf]].nil? stdout_matches_failure[r[:all_buf]] << @command_to_target[r[:command].object_id] end end # output => [targets ...] stdout_matches_success.each_pair do |k,v| hosts = @rangeclient.compress v # puts "#{hosts}: '#{k.chomp}'" puts "SUCCESS: #{hosts}: #{k}" end stdout_matches_failure.each_pair do |k,v| hosts = @rangeclient.compress v puts "FAILURE: #{hosts}: #{k}" end ## Dont collapse similar resutls else result.each do |r| target = @command_to_target[r[:command].object_id] if (r[:retval].success?) puts "#{target}:SUCCESS: #{r[:all_buf]}\n" else exit_code = r[:retval].exitstatus.to_s if(!r[:retval].nil?) puts "#{target}:FAILURE[#{exit_code}]: #{r[:all_buf]}\n" end end end end |
#parse(argv) ⇒ Object
Parses a list of arguments, and yells at us if any are wrong.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/cli.rb', line 19 def parse(argv) @defs = Hash[@options.map{|k,v| [k, " (default: #{v})"] } ] optparse = OptionParser.new do |opts| opts.on('-r', '--range RANGE', 'currently takes a CSV list' + @defs[:range].to_s ) do |arg| @options[:range] = arg end opts.on('--hostlist x,y,z', Array, 'List of hostnames to execute on' + @defs[:hostlist].to_s) do |arg| @options[:hostlist] = arg end opts.on('-f', '--file FILE', 'List of hostnames in a FILE use (/dev/stdin) for reading from stdin' + @defs[:file].to_s) do |arg| @options[:file] = arg end opts.on('-m', '--maxflight 200', 'How many subprocesses? 50 by default' + @defs[:maxflight].to_s) do |arg| @options[:maxflight] = arg end opts.on('-t', '--timeout 60', 'How many seconds may each individual process take? 0 for no timeout' + @defs[:timeout].to_s) do |arg| @options[:timeout] = arg end opts.on('-g', '--global_timeout 0', 'How many seconds for the whole shebang 0 for no timeout' + @defs[:global_timeout].to_s) do |arg| @options[:global_timeout] = arg end opts.on('-c', '--collapse', "Collapse similar output " + @defs[:collapse].to_s) do |arg| @options[:collapse] = arg end opts.on('-v', '--verbose', "Verbose output" + @defs[:verbose].to_s) do |arg| @options[:verbose] = arg end opts.on('-d', '--debug', "Debug output" + @defs[:debug].to_s) do |arg| @options[:debug] = arg end opts.on('--json', "Output results as JSON" + @defs[:json_out].to_s) do |arg| @options[:json_out] = arg end opts.on('--hntoken HOSTNAME', "Token used for HOSTNAME substitution" + @defs[:hostname_token].to_s) do |arg| @options[:hostname_token] = arg end @extra_options.call(opts, @options) if !@extra_options.nil? # option to merge stdin/stdout into one buf? how should this work? # option to ignore as-we-go yield output - this is off by default now except for success/fail end optparse.parse! argv if [:range] || [:collapse] require 'rangeclient' @rangeclient = Range::Client.new end ## Get targets from -r or -f or --hostlist @targets = [] if ([:range].nil? and [:file].nil? and [:hostlist].nil?) raise "Error, need -r or -f or --hostlist option" end if (![:range].nil?) @targets.push *@rangeclient.([:range]) end if (![:file].nil?) targets_fd = File.open([:file]) targets_fd.read.each_line { |x| @targets << x.chomp } end if (![:hostlist].nil?) @targets.push *[:hostlist] end raise "no targets specified. Check your -r, -f or --hostlist inputs" if @targets.size.zero? raise "need command to run" if argv.size.zero? raise "too many arguments" if argv.size != 1 @command = argv.first end |
#runcmd ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/cli.rb', line 98 def runcmd m = MultipleCmd.new # We let the caller build the command m.commands = @targets.map do |t| yield(@command.gsub(@options[:hostname_token], t), t) end @command_to_target = Hash.new @targets.size.times do |i| @command_to_target[m.commands[i].object_id] = @targets[i] end m.yield_startcmd = lambda { |p| puts "#{@command_to_target[p.command.object_id]}: starting" } if @options[:verbose] m.yield_wait = lambda { |p| puts "#{p.success? ? 'SUCCESS' : 'FAILURE'} #{@command_to_target[p.command.object_id]}: '#{p.stdout_buf}'" } if @options[:verbose] # todo, from mssh m.yield_wait = lambda { |p| puts "#{@command_to_target[p.command.object_id]}: finished" } if @options[:verbose] # was commented out in mcmd already: m.yield_proc_timeout = lambda { |p| puts "am killing #{p.inspect}"} m.perchild_timeout = @options[:timeout].to_i m.global_timeout = @options[:global_timeout].to_i m.maxflight = @options[:maxflight].to_i m.verbose = @options[:verbose] m.debug = @options[:debug] return m.run end |