module DbSucker::Application::Dispatch

Public Instance Methods

_default_listing(identifier, ctn, variation, var) click to toggle source

default action if no variation is given

# File lib/db_sucker/application/dispatch.rb, line 366
def _default_listing identifier, ctn, variation, var
  db_table_listing(ctn ? [[identifier, ctn]] : cfg)
end
_dispatch_stat_tmp_display(files, directories, managed, cleanup = false, sftp = false) click to toggle source

helper for dispatch_stat_tmp

# File lib/db_sucker/application/dispatch.rb, line 265
def _dispatch_stat_tmp_display files, directories, managed, cleanup = false, sftp = false
  log "Directories: #{c directories.count, :blue}"
  log "      Files: #{c files.count, :blue} #{c "("}#{c managed.count, :blue}#{c " managed)"}"
  log "       Size: #{c human_bytes(files.map(&:second).sum), :blue} #{c "("}#{c human_bytes(managed.map(&:second).sum), :blue} #{c "managed)"}"

  if cleanup
    if managed.any?
      log c("WE ONLY SIMULATE! Nothing will be deleted!", :green) if opts[:simulate]
      warning "----------- Removing #{managed.count} managed files! Press Ctrl-C to abort -----------"
      managed.each{|f, s| warning "  REMOVE #{c "#{f}", :magenta} #{c human_bytes(s), :cyan}" }
      warning "----------- Removing #{managed.count} managed files! Press Ctrl-C to abort -----------"
      sleep 3
      4.times {|n| log "Cleaning up in #{3 - n}..." ; sleep 1 ; rll }

      managed.each do |f, s|
        if opts[:simulate]
          warning "(simulate)   Removing #{f}..."
        else
          warning "Removing #{f}..."
          sftp ? sftp.remove!(f) : File.unlink(f)
        end
      end
    else
      log c("No managed files found, nothing to cleanup.", :green)
    end
  end
end
_list_databases(identifier, ctn, variation, var) click to toggle source

via -l/–list-databases

# File lib/db_sucker/application/dispatch.rb, line 333
def _list_databases identifier, ctn, variation, var
  return unless opts[:list_databases]
  log "Listing databases for identifier #{c identifier, :magenta}#{c "..."}"
  dbs = ctn.database_list(opts[:list_tables])
  print_db_table_list ctn.hostname, dbs
  throw :dispatch_handled
end
_list_tables(identifier, ctn, variation, var) click to toggle source

via -t/–list-tables

# File lib/db_sucker/application/dispatch.rb, line 342
def _list_tables identifier, ctn, variation, var
  return if !(opts[:list_tables].present? && opts[:list_tables] != :all)
  print_db_table_list ctn.hostname, [[opts[:list_tables], ctn.table_list(opts[:list_tables])]]
  throw :dispatch_handled
end
_suck_variation(identifier, ctn, variation, var) click to toggle source

default action if variation given

# File lib/db_sucker/application/dispatch.rb, line 349
def _suck_variation identifier, ctn, variation, var
  if ctn && (var || (@opts[:suck_only].any? || @opts[:suck_except].any?))
    var ||= ctn.variation("default")
    begin
      trap_signals
      @sklaventreiber = SklavenTreiber.new(self, uniqid)
      @sklaventreiber.spooled do
        @sklaventreiber.whip_it!(ctn, var)
      end
    ensure
      release_signals
    end
    throw :dispatch_handled
  end
end
available_actions() click to toggle source
# File lib/db_sucker/application/dispatch.rb, line 20
def available_actions
  methods.select{|m| m.to_s.start_with?("dispatch_") }.map{|s| s.to_s.gsub(/\Adispatch_/, "").to_sym }
end
configful_dispatch(identifier, variation, &block) click to toggle source
# File lib/db_sucker/application/dispatch.rb, line 24
def configful_dispatch identifier, variation, &block
  log "Using config directory #{c core_cfg_path.to_s, :magenta}"

  all_cfgs = cfg.yml_configs(true)
  enabled  = cfg.yml_configs(false)
  disabled = all_cfgs - enabled
  r = c("Found #{c all_cfgs.count, :blue} #{c "config files"}")
  r << c(" (#{c "#{disabled.count} disabled", :red}#{c ")"}") if disabled.any?
  log r << c("...")

  cfg.load_all_configs
  ctn = cfg.get(identifier)

  if identifier.present? && !ctn
    abort "Identifier `#{identifier}' couldn't be found!", 1
  end

  if ctn && variation && !(var = ctn.variation(variation))
    abort "Variation `#{variation}' for identifier `#{identifier}' couldn't be found!", 1
  end

  begin
    ctn.try(:ssh_begin)
    block.call(identifier, ctn, variation, var)
  ensure
    ctn.try(:ssh_end)
  end
end
dispatch(action = (@opts[:dispatch] || :help)) click to toggle source
# File lib/db_sucker/application/dispatch.rb, line 4
def dispatch action = (@opts[:dispatch] || :help)
  if respond_to?("dispatch_#{action}")
    has_action = true
    fire(:dispatch_before, action)
    send("dispatch_#{action}")
  else
    fire(:dispatch_before, false)
    abort("unknown action `#{action}'\nRegistered actions: #{available_actions.join(", ")}")
  end
rescue StandardError => ex
  fire(:dispatch_after, has_action ? action : false, ex)
  raise ex
else
  fire(:dispatch_after, has_action ? action : false)
end
dispatch_cleanup_tmp() click to toggle source

via –cleanup-tmp

# File lib/db_sucker/application/dispatch.rb, line 328
def dispatch_cleanup_tmp
  dispatch_stat_tmp(true)
end
dispatch_cloop() click to toggle source

via -a/–action cloop

# File lib/db_sucker/application/dispatch.rb, line 60
def dispatch_cloop
  begin
    trap_signals
    @sklaventreiber = SklavenTreiber.new(self, uniqid)
    @sklaventreiber.spooled do
      @opts[:stdout].disable
      hook(:prompt_start) { @opts[:stdout].enable }
      hook(:prompt_stop) { @opts[:stdout].disable(true) }
      begin
        @sklaventreiber._init_window
        loop do
          break if $core_runtime_exiting
          sleep 0.1
        end
      ensure
        sandboxed { @sklaventreiber.window.try(:stop) }
      end
    end
  ensure
    release_signals
  end
end
dispatch_console() click to toggle source

via -a/–action console

# File lib/db_sucker/application/dispatch.rb, line 84
def dispatch_console
  configful_dispatch(ARGV.shift, ARGV.shift) do |identifier, ctn, variation, var|
    begin ; require "pry" ; rescue LoadError ; end
    ::Kernel.binding.pry
  end
end
dispatch_generate_config() click to toggle source

via –generate

# File lib/db_sucker/application/dispatch.rb, line 249
def dispatch_generate_config
  cfg_name = @opts[:config_name] || "default"
  cfg_file = "#{core_cfg_path}/#{cfg_name}.yml"
  puts c("Generating container configuration file `#{cfg_name}'")
  if File.exist?(cfg_file)
    abort "Conflict, file already exists: #{cfg_file}", 1
  else
    puts c("Writing #{cfg_file}", :green)
    FileUtils.mkdir_p(core_cfg_path)
    FileUtils.cp("#{ROOT}/doc/container_example.yml", cfg_file)
    editor = ENV["EDITOR"].presence
    exec("#{editor.chomp} #{cfg_file}") if editor
  end
end
dispatch_help() click to toggle source

via -h/–help

# File lib/db_sucker/application/dispatch.rb, line 192
def dispatch_help
  colorized_help = @optparse.to_s.split("\n").map do |l|
    if l.start_with?("Usage:")
      lc = l.split(" ")
      "#{c lc[0]} #{c lc[1], :blue} #{c lc[2..-1].join(" "), :cyan}"
    elsif l.start_with?("#")
      c(l, :blue)
    elsif l.strip.start_with?("-")
      "#{c l.to_s[0...33], :cyan}#{c l[33..-1]}"
    else
      c(l)
    end
  end
  puts nil, colorized_help, nil
  puts c("The current config directory is #{c core_cfg_path.to_s, :magenta}"), nil
end
dispatch_index() click to toggle source

default actions in order

# File lib/db_sucker/application/dispatch.rb, line 371
def dispatch_index
  configful_dispatch(ARGV.shift, ARGV.shift) do |identifier, ctn, variation, var|
    catch :dispatch_handled do
      [:_list_databases, :_list_tables, :_suck_variation, :_default_listing].each do |meth|
        __send__(meth, identifier, ctn, variation, var)
      end
    end
  end
end
dispatch_info() click to toggle source

via -v/–version

# File lib/db_sucker/application/dispatch.rb, line 210
def dispatch_info
  your_version = Gem::Version.new(DbSucker::VERSION)
  puts c ""
  puts c("     Your version: ", :blue) << c("#{your_version}", :magenta)

  print c("  Current version: ", :blue)
  if @opts[:check_for_updates]
    require "net/http"
    print c("checking...", :blue)

    begin
      current_version = Gem::Version.new Net::HTTP.get_response(URI.parse(DbSucker::UPDATE_URL)).body.strip

      if current_version > your_version
        status = c("#{current_version} (consider update)", :red)
      elsif current_version < your_version
        status = c("#{current_version} (ahead, beta)", :green)
      else
        status = c("#{current_version} (up2date)", :green)
      end
    rescue
      status = c("failed (#{$!.message})", :red)
    end

    print "#{"\b" * 11}#{" " * 11}#{"\b" * 11}" # reset line
    puts status
  else
    puts c("check disabled", :red)
  end

  # more info
  puts c ""
  puts c "  DbSucker is brought to you by #{c "bmonkeys.net", :green}"
  puts c "  Contribute @ #{c "github.com/2called-chaos/db_sucker", :cyan}"
  puts c "  Eat bananas every day!"
  puts c ""
end
dispatch_sshdiag() click to toggle source

via -a/–action sshdiag

# File lib/db_sucker/application/dispatch.rb, line 109
def dispatch_sshdiag
  _identifier, _ctn = false, false, false
  idstr = ARGV.shift
  varstr = ARGV.shift

  configful_dispatch(idstr, varstr) do |identifier, ctn, variation, var|
    unless ctn
      abort "This test requires a config identifier with an SSH connection!"
    end

    log c("\nPlease wait while we run some tests...\n", :blue)
    _identifier = identifier
    _ctn = ctn
    channels = []
    monitor = Monitor.new
    stop = false
    maxsessions = :unknown
    begin
      t = Thread.new {
        begin
          loop do
            ctn.loop_ssh(0.1) { monitor.synchronize { channels.any? } }
          end
        rescue DbSucker::Application::Container::SSH::ChannelOpenFailedError
          monitor.synchronize do
            maxsessions = channels.length - channels.select{|c| c[:open_failed] }.length
            stop = true
            print "!"
          end
          retry
        end
      }
      250.times do
        break if monitor.synchronize { stop }
        c, r = ctn.blocking_channel_result("sleep 900", blocking: false, channel: true, use_sh: true)
        monitor.synchronize do
          channels << c
          print "+"
        end
        sleep 0.1
      end
    ensure
      debug "Stopping sessions (#{channels.length})..."
      puts # newline for style
      i = 1
      loop do
        break if monitor.synchronize { channels.empty? }
        c = monitor.synchronize { channels.shift }
        debug "Channel ##{i} #{c[:pid] ? "with PID #{c[:pid]}" : "has no PID"}"
        ctn.kill_remote_process(c[:pid]) if c[:pid]
        print "-"
        i += 1
      end
      maxsessions = "#{maxsessions}+" if maxsessions.to_i >= 250
      log c("\n\nSSH MaxSessions: #{c maxsessions, :magenta}", :cyan)
      log "This value determines how many sessions we can multiplex over a single TCP connection."
      log "Currently, DbSucker can only utilize one connection, thus this value defines the maxmium concurrency."
      log "If you get errors you can either"
      log "  * increase the SSHd `MaxSessions' setting on the remote (if you can)"
      log "  * reduce the amount of workers and/or remote slots"
      log "  * fix the mess that is this tool, visit #{c "https://github.com/2called-chaos/db_sucker", :blue}"
      t.kill.join
    end
  end
rescue Net::SSH::AuthenticationFailed => ex
  notify_exception(ex)
  log "\nDbSucker can't authenticate with the remote host, see exception."
  log "  * username correct?"
  log "  * password/keyfile correct?"
  log "  * check remote /var/log/auth.log?"
rescue SocketError => ex
  notify_exception(ex)
  log "\nDbSucker can't establish a connection to the remote host " << c(cfg.get(idstr).source["ssh"]["hostname"], :magenta)
  log "  * typo in hostname / IP?"
  log "  * firewall?"
end
dispatch_stat_tmp(cleanup = false) click to toggle source

via –stat-tmp

# File lib/db_sucker/application/dispatch.rb, line 294
def dispatch_stat_tmp cleanup = false
  configful_dispatch(ARGV.shift, ARGV.shift) do |identifier, ctn, variation, var|
    if ctn
      ctn.sftp_begin do |sftp|
        log c("Analyzing ") << c("remote", :cyan) << c(" temp directory #{c ctn.tmp_path, :magenta}")
        begin
          files = sftp.dir.glob("#{ctn.tmp_path}", "**/*")
        rescue Net::SFTP::StatusException => ex
          if ex.message["no such file"]
            abort "Destination directory `#{ctn.tmp_path}' does not exist on the remote side!"
          else
            raise
          end
        end

        d_files = files.select(&:file?).map{|f| ["#{ctn.tmp_path}/#{f.name}", f.attributes.size] }
        d_directories = files.select(&:directory?).map{|f| ["#{ctn.tmp_path}/#{f.name}"] }
        d_managed = files.select(&:file?).select{|f| f.name.end_with?(".dbsc", ".dbsc.tmp", ".dbsc.gz") }.map{|f| ["#{ctn.tmp_path}/#{f.name}", f.attributes.size] }
        _dispatch_stat_tmp_display(d_files, d_directories, d_managed, cleanup, sftp)
      end
    else
      log c("Analyzing ") << c("local", :cyan) << c(" temp directory #{c core_tmp_path, :magenta}")
      files = Dir.glob("#{core_tmp_path}/**/*")

      managed_files = files
      d_files = files.select{|f| File.file?(f) }.map{|f| [f, File.size(f)] }
      d_directories = files.select{|f| File.directory?(f) }
      d_managed = files.select{|f| File.file?(f) && File.basename(f).end_with?(".dbsc", ".dbsc.tmp", ".dbsc.gz") }.map{|f| [f, File.size(f)] }
      _dispatch_stat_tmp_display(d_files, d_directories, d_managed, cleanup)
    end
  end
end
dispatch_threadtest() click to toggle source

via -a/–action threadtest

# File lib/db_sucker/application/dispatch.rb, line 92
def dispatch_threadtest
  t = Thread.new { Thread.stop }
  i, m = 1, [0, nil, nil]
  while i < 3
    m[0] += i == 1 ? -1 : 1
    t.priority = m[0]
    if t.priority != m[0]
      m[i] = t.priority
      m[0] = 0
      i += 1
    end
  end
  t.kill.join
  puts "Thread priority: -#{m[1].abs}..+#{m[2].abs}"
end