class Hotdog::Commands::SshAlike
Public Instance Methods
define_options(optparse, options={})
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 13 def define_options(optparse, options={}) default_option(options, :ssh_options, {}) default_option(options, :color, :auto) default_option(options, :max_parallelism, Parallel.processor_count * 2) default_option(options, :shuffle, false) default_option(options, :ssh_config, nil) # we must not need to run ssh against terminated hosts default_option(options, :status, STATUS_RUNNING) optparse.on("-C", "Enable compression.") do |v| options[:ssh_options]["Compression"] = "yes" end optparse.on("-F SSH_CONFIG", "Specifies an alternative per-user SSH configuration file.") do |configfile| options[:ssh_config] = configfile end optparse.on("--dry-run", "Dry run.") do |v| options[:dry_run] = v end optparse.on("-o SSH_OPTION", "Passes this string to ssh command through shell. This option may be given multiple times") do |ssh_option| ssh_option_key, ssh_option_value = ssh_option.split("=", 2) options[:ssh_options][ssh_option_key] = ssh_option_value end optparse.on("-i SSH_IDENTITY_FILE", "SSH identity file path") do |path| options[:ssh_options]["IdentityFile"] = path end optparse.on("-A", "Enable agent forwarding", TrueClass) do |b| options[:ssh_options]["ForwardAgent"] = "yes" end optparse.on("-p PORT", "Port of the remote host", Integer) do |port| options[:ssh_options]["Port"] = port end optparse.on("-u SSH_USER", "SSH login user name") do |user| options[:ssh_options]["User"] = user end optparse.on("--filter=COMMAND", "Command to filter search result.") do |command| options[:filter_command] = command end optparse.on("-P PARALLELISM", "Max parallelism", Integer) do |n| options[:max_parallelism] = n end optparse.on("--color=WHEN", "--colour=WHEN", "Enable colors") do |color| options[:color] = color end optparse.on("--shuffle", "Shuffle result") do |v| options[:shuffle] = v end end
run(args=[], options={})
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 60 def run(args=[], options={}) expression = rewrite_expression(args.join(" ").strip) begin node = parse(expression) rescue Parslet::ParseFailed => error STDERR.puts("syntax error: " + error.cause.ascii_tree) exit(1) end result0 = evaluate(node, self) tuples, fields = get_hosts_with_search_tags(result0, node) tuples = filter_hosts(tuples) validate_hosts!(tuples, fields) logger.info("target host(s): #{tuples.map {|tuple| tuple.first }.inspect}") run_main(tuples.map {|tuple| tuple.first }, options) end
Private Instance Methods
build_command_options(options={})
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 123 def build_command_options(options={}) cmdline = [] if options[:ssh_config] cmdline << "-F" << File.expand_path(options[:ssh_config]) end cmdline += options[:ssh_options].flat_map { |k, v| ["-o", "#{k}=#{v}"] } if VERBOSITY_TRACE <= options[:verbosity] cmdline << "-v" end cmdline end
build_command_string(host, command=nil, options={})
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 135 def build_command_string(host, command=nil, options={}) # build ssh command cmdline = Shellwords.shellsplit(options.fetch(:ssh_command, "ssh")) + build_command_options(options) + [host] if command cmdline << "--" << command end Shellwords.join(cmdline) end
color_code(index)
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 203 def color_code(index) if index color = 31 + (index % 6) else color = 36 end end
each_readable(read_list, timeout=1) { |r| ... }
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 188 def each_readable(read_list, timeout=1) loop do # we cannot look until IO#eof? since it will block for pipes # http://ruby-doc.org/core-2.4.0/IO.html#method-i-eof-3F rs = Array(IO.select(read_list, [], [], timeout)).first if r = Array(rs).first begin yield r rescue EOFError => error break end end end end
exec_command(identifier, cmdline, options={})
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 155 def exec_command(identifier, cmdline, options={}) output = options.fetch(:output, true) output_lock = options[:output_lock] || Mutex.new logger.debug("execute: #{cmdline}") if use_color? color = color_code(options[:index]) else color = nil end if options[:infile] cmdline = "cat #{Shellwords.shellescape(options[:infile])} | #{cmdline}" end cmderr, child_cmderr = IO.pipe IO.popen(cmdline, in: :close, err: child_cmderr) do |cmdout| i = 0 each_readable([cmderr, cmdout]) do |readable| raw = readable.readline if output output_lock.synchronize do if readable == cmdout STDOUT.puts(prettify_output(raw, i, color, identifier)) i += 1 else STDERR.puts(prettify_output(raw, nil, nil, identifier)) end end end end end $?.success? # $? is thread-local variable end
filter_hosts(tuples)
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 91 def filter_hosts(tuples) if options[:filter_command] filtered_tuples = Parallel.map(tuples, in_threads: parallelism(tuples)) { |tuple| cmdline = build_command_string(tuple.first, options[:filter_command], options) [tuple, exec_command(tuple.first, cmdline, output: false)] }.select { |_host, stat| stat }.map { |tuple, _stat| tuple } if tuples == filtered_tuples tuples else logger.info("filtered host(s): #{(tuples - filtered_tuples).map {|tuple| tuple.first }.inspect}") filtered_tuples end else tuples end end
parallelism(hosts)
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 87 def parallelism(hosts) [options[:max_parallelism], hosts.size].compact.min end
prettify_output(raw, i, color, identifier)
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 211 def prettify_output(raw, i, color, identifier) buf = [] if identifier if color buf << ("\e[0;#{color}m") end buf << identifier buf << ":" if i buf << i.to_s buf << ":" end if color buf << "\e[0m" end end buf << raw buf.join end
rewrite_expression(expression)
click to toggle source
Calls superclass method
Hotdog::Commands::Search#rewrite_expression
# File lib/hotdog/commands/ssh.rb, line 79 def rewrite_expression(expression) expression = super(expression) if options[:shuffle] expression = "SHUFFLE((#{expression}))" end expression end
run_main(hosts, options={})
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 119 def run_main(hosts, options={}) raise(NotImplementedError) end
use_color?()
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 144 def use_color? case options[:color] when :always true when :never false else STDOUT.tty? end end
validate_hosts!(tuples, fields)
click to toggle source
# File lib/hotdog/commands/ssh.rb, line 112 def validate_hosts!(tuples, fields) if tuples.length < 1 logger.error("no match found") exit(1) end end