module EY module Backup module CLI #rename to option parser and config loader extend self def run(argv) options = default_options.merge(opt_parse(argv)) verify_restore if options[:command] == :restore and !options[:force] config_path = options[:config] || "/etc/.#{options[:engine]}.backups.yml" config_for(config_path).merge(options) end def default_options { :command => :new_backup, :format => "gzip", :engine => 'mysql', :verbose => false, } end def verify_restore res = '' puts "This will overwrite your database, are you sure you would like to proceed (Y/n)?" Timeout::timeout(30){ res = gets.strip } abort("You indicated '#{res}', exiting!") unless res.upcase == 'Y' end def opt_parse(argv) # Build a parser for the command line arguments options = {} opts = OptionParser.new do |opts| opts.version = EY::CloudServer::VERSION puts '' # add a blank line opts.banner = "Usage: eybackup [-flag] [argument]" opts.define_head " eybackup: manage dump (mysqldump/pg_dump) style backups of your database." opts.separator '*'*80 opts.on("-l", "--list-backup DATABASE", "List backups for DATABASE") do |db| if db == "all" db = nil end options[:db] = db options[:command] = :list end opts.on("-e", "--engine DATABASE_ENGINE", "The database engine. ex: mysql, postgresql.") do |engine| options[:engine] = engine end opts.on("-n", "--new-backup", "Create a new backup (default)") do options[:command] = :new_backup end opts.on("-c", "--config CONFIG", "Use config file.") do |config| options[:config] = config end opts.on("-b", "--bucket BUCKET", "Override default S3 bucket name. (Be Careful!)") do |bucket| options[:backup_bucket] = bucket end opts.on("-t", "--tmp_dir TMPDIR", "Use the given directory for temporary storage.") do |tmp_dir| options[:tmp_dir] = tmp_dir end opts.on("-k", "--key KEYID", "Public key ID to use for the backup operation") do |key_id| options[:key_id] = key_id end opts.on("-q", "--quiet", "Suppress output to STDOUT") do options[:quiet] = true end opts.on("-s", "--split_size INTEGER", "Maximum size of a single backup file before splitting.") do |split_size| options[:split_size] = split_size.to_i end opts.on("-v", "--verbose", "Show verbose output") do options[:verbose] = true end opts.on("-d", "--download BACKUP_INDEX", "Download the backup specified by index.", ' Run `eybackup -l #{db_name}` to get the index.', ' BACKUP_INDEX uses the format #{index_number}:#{db_name}') do |index_and_db| options[:command] = :download db, index = split_index(index_and_db) options[:index] = index options[:db] = db end opts.on("-r", "--restore BACKUP_INDEX", "Download and apply the backup specified by index.", " **WARNING!** will overwrite the current db with the backup.", ' Run `eybackup -l #{db_name}` to get the index.', ' BACKUP_INDEX uses the format #{index_number}:#{db_name}') do |index_and_db| options[:command] = :restore db, index = split_index(index_and_db) options[:index] = index options[:db] = db end options[:force] = false opts.on("-f", "--force", "Force backup restore, bypass confirmation prompts.", " For use with automated restore operations (e.g. Staging).") do options[:force] = true end end opts.parse!(argv) options end def split_index(index) index.split(':').reverse end def config_for(filename) if File.exist?(filename) # Make the loaded config have symbols rather than strings config_orig = YAML::load(File.read(filename)) config = {} config_orig.each do |key, val| config[key.to_sym] = val end config[:environment] ||= config[:env] config else abort "You need to have a backup file at #{filename}" end end end end end