class Dumpr::Driver::Base

abstract interface for all drivers

Attributes

database[R]
destination[R]
destination_dumpfile[R]
destination_host[R]
dump_options[R]
dumpdir[R]
dumpfile[R]
gzip[R]
gzip_options[R]
host[R]
import_options[R]
opts[R]
password[R]
port[R]
tables[R]
user[R]

Public Class Methods

new(opts) click to toggle source
# File lib/dumpr/driver.rb, line 37
def initialize(opts)
  self.configure(opts)
end

Public Instance Methods

configure(opts) click to toggle source
# File lib/dumpr/driver.rb, line 41
def configure(opts)
  opts = (@opts||{}).merge(opts)
  # db connection settings
  @host = opts[:host] || "localhost"
  @port = opts[:port]
  @user = opts[:user] or raise BadConfig.new "user is required"
  @password = (opts[:password]  || opts[:pass]) # or raise BadConfig.new "password is required"

  # dump all_databases or specific database(s)
  @all_databases = nil
  @database = nil
  @databases = nil
  @tables = nil
  if (opts[:database] || opts[:db])
    @database = (opts[:database] || opts[:db])
    @tables = [opts[:table], opts[:tables]].flatten.uniq.compact
  elsif opts[:databases]
    @databases = [opts[:databases]].flatten.uniq.compact # not used/supported yet
  elsif opts[:all_databases]
    @all_databases = true
  else
    #raise BadConfig.new "database is required"
  end

  # dump settings
  @gzip = opts[:gzip].nil? ? true : opts[:gzip]
  @gzip_options = opts[:gzip_options] || "-9"
  @dumpdir = opts[:dumpdir] || Dir.pwd #"./"
  @dumpfile = (opts[:file] || opts[:dumpfile] || opts[:filename]) or raise BadConfig.new "[file] is required"
  @dumpfile = @dumpfile.to_s.dup # this is frozen?
  @dumpfile = @dumpfile[0].chr == "/" ? @dumpfile : File.join(@dumpdir, @dumpfile)
  @dumpfile.chomp!(".gz")
  # (optional) :destination is where dumps are exported to, and can be a remote host:path
  @destination = opts[:destination] || @dumpfile
  if @destination.include?(":")
    @destination_host, @destination_dumpfile = @destination.split(":")[0], @destination.split(":")[1]
  else
    @destination_host, @destination_dumpfile = "localhost", @destination
  end
  # destination might be a path only, so build the entire filepath
  if File.extname(@destination_dumpfile) == ""
    @destination_dumpfile = File.join(@destination_dumpfile, File.basename(@dumpfile))
  end
  @destination_dumpfile.chomp!(".gz")
  @dump_options = opts[:dump_options]
  @import_options = opts[:import_options]

  # set / update logger
  if opts[:logger]
    @logger = opts[:logger]
  elsif opts[:log_file]
    @logger = Logger.new(opts[:log_file])
  end
  @logger = Logger.new(STDOUT) if !@logger
  @logger.level = opts[:log_level] if opts[:log_level] # expects integer

  @opts = opts
end
decompress() click to toggle source
# File lib/dumpr/driver.rb, line 185
def decompress
  if File.exists?(@dumpfile + ".gz")
    if File.exists?(@dumpfile) && !@opts[:force]
      logger.warn "skipping decompress because #{@dumpfile} already exists."
    else
      logger.debug "decompressing..."
      run "gzip -d -f #{@dumpfile}.gz"
    end
  else
    logger.warn "decompress failed. #{@dumpfile}.gz does not exist!"
  end
end
dump() click to toggle source

creates @dumpfile pipes :dump_cmd to gzip, rather than write the file to disk twice if @destination is defined, it then moves the dump to the @destination, which can be a remote host:path

# File lib/dumpr/driver.rb, line 125
def dump
  logger.debug("begin dump")
  if dump_installed? != true
    raise MissingDriver.new "#{self.class} does not appear to be installed.\nCould not find command `#{dump_cmd.to_s.split.first}`"
  end
  dumpfn = @dumpfile + (@gzip ? ".gz" : "")
  Util.with_lockfile("localhost", dumpfn, @opts[:force]) do

    logger.debug "preparing dump..."
    if !File.exists?(File.dirname(dumpfn))
      run "mkdir -p #{File.dirname(dumpfn)}"
    end

    # avoid overwriting dump files..
    if File.exists?(dumpfn)
      if @opts[:force]
        logger.warn "#{dumpfn} exists, moving it to #{dumpfn}.1"
        #run "rm -f #{dumpfn}.1;"
        run "mv #{dumpfn} #{dumpfn}.1"
      else
        logger.warn "#{dumpfn} already exists!"
        raise DumpFileExists.new "#{dumpfn} already exists!"
      end
    end

    logger.debug "dumping..."
    if @gzip
      run "#{dump_cmd} | gzip #{gzip_options} > #{dumpfn}"
    else
      run "#{dump_cmd} > #{dumpfn}"
    end
    dumpsize = Util.human_file_size("localhost", dumpfn)
    logger.info("generated #{dumpfn} (#{dumpsize})")

    if @destination
      if remote_destination?
        logger.debug "exporting to #{@destination_host}..."
        Util.with_lockfile(@destination_host, @destination_dumpfile, @opts[:force]) do
          run "scp #{dumpfn} #{@destination_host}:#{@destination_dumpfile}#{@gzip ? '.gz' : ''}"
        end
      elsif @destination_dumpfile && @destination_dumpfile+(@gzip ? '.gz' : '') != dumpfn
        logger.debug "exporting..."
        destdir = File.dirname(@destination_dumpfile)
        run "mkdir -p #{destdir}" if !Util.dir_exists?("localhost", destdir)
        Util.with_lockfile("localhost", @destination_dumpfile, @opts[:force]) do
          run "mv #{dumpfn} #{@destination_dumpfile}#{@gzip ? '.gz' : ''}"
        end
      end
    end

  end # with_lockfile
  logger.debug("end dump")
end
dump_cmd() click to toggle source
# File lib/dumpr/driver.rb, line 112
def dump_cmd
  raise BadConfig.new "#{self.class} has not defined dump_cmd"
end
dump_installed?() click to toggle source
# File lib/dumpr/driver.rb, line 104
def dump_installed?
  raise BadConfig.new "#{self.class} has not defined dump_installed?"
end
import() click to toggle source
# File lib/dumpr/driver.rb, line 198
def import
  if import_installed? != true
    raise MissingDriver.new "#{self.class} does not appear to be installed.\nCould not find command `#{import_cmd.to_s.split.first}`"
  end
  Util.with_lockfile("localhost", @dumpfile, @opts[:force]) do
    decompress if @gzip

    if !File.exists?(@dumpfile)
      raise "Cannot import #{@dumpfile} because it does not exist!"
    else
      dumpsize = Util.human_file_size("localhost", @dumpfile)
      logger.info("importing #{@dumpfile} (#{dumpsize})")
      run import_cmd
    end

  end # with_lockfile
end
import_cmd() click to toggle source

IMPORTING

# File lib/dumpr/driver.rb, line 181
def import_cmd
  raise BadConfig.new "#{self.class} has not defined import_cmd!"
end
import_installed?() click to toggle source
# File lib/dumpr/driver.rb, line 108
def import_installed?
  raise BadConfig.new "#{self.class} has not defined import_installed?"
end
logger() click to toggle source
# File lib/dumpr/driver.rb, line 100
def logger
  @logger
end
remote_destination?() click to toggle source

DUMPING + EXPORTING

# File lib/dumpr/driver.rb, line 118
def remote_destination?
  @destination_host && @destination_host != "localhost"
end

Protected Instance Methods

run(cmd) click to toggle source
# File lib/dumpr/driver.rb, line 222
def run(cmd)
  start_time = Time.now
  logger.info "running command: #{scrub_cmd cmd}"
  stdout = `#{cmd}`
  took_sec = (Time.now - start_time).round()
  if $?.success?
    logger.info "finished (took #{took_sec}s)"
  else
    logger.error "failed (took #{took_sec}s) status: #{$?.exitstatus}"
    raise CommandFailure.new("Aborting because the following command failed: #{scrub_cmd cmd}")
  end
end
scrub_cmd(cmd) click to toggle source
# File lib/dumpr/driver.rb, line 218
def scrub_cmd(cmd)
  cmd.gsub(/password=[^\s]+/, 'password=xxxxxx')
end