#!/usr/bin/env ruby $LOAD_PATH.unshift(File.expand_path("../../lib/", __FILE__)) require 'rubygems' require 'yaml' require 'digest' require 'fileutils' require 'openssl' require 'socket' require 'helpers' require 'slop' require 'fog' require 'progressbar' require 'lzoruby' require 'zlib' require 'base64' require 'backup' require 'encbsconfig' begin if lock_exists? puts_fail "Lock file exists. Make sure that an encbs instance does not exists." else create_lock end opts = Slop.parse :help => true do on :a, :add, "Add path to backup", true on :b, :bucket, "Set Amazon S3 bucket to backup", true on :c, :config, "Use config file to upload backup", true on :colorize, "Colorize print to console" on :compression, "Use compression for files (option: gzip, lzo)", true on :d, :date, "Date for backup restore (default: last)", true on :g, :generate, "Generate RSA keys (option: 4096, 2048)", true on :h, :hostname, "Set hostname (default: system)", true on :i, :increment, "Use increment mode for backup (default: false)" on :j, :jar, "Versions of jar (option: hash or path)", true on :k, :key, "Set API key to access Amazon S3", true on :l, :local, "Backup in local directory", true on :list, "List of jars" on :p, :purge, "Remove previous backup(s)" on :r, :rescue, "Return data from backup (option: jar, path or filter)", true on :s, :secret, "Set API secret to access Amazon S3", true on :size, "RSA private key length (default: 4096)", true on :t, :to, "Path to recovery (default: /)", true on :timeout, "Timeout(sec) to try pushing into cloud (default: 60s)", true on :token, "RSA key to encrypt/decrypt backup data", true on :v, :verbose, "Verbose mode" banner "Usage:\n $ encbs [options]\n\nOptions:" end @config = EncbsConfig.new if ARGV.empty? if File.exists?("#{Dir.getwd}/Encbsfile") @config.load "#{Dir.getwd}/Encbsfile" else puts opts.help exit end end @config.load opts[:config] if opts.config? $PRINT_VERBOSE = @config.verbose || opts.verbose? $COLORIZE = @config.colorize || opts.colorize? if opts.generate? bits = opts[:generate].to_i puts_fail "Unsupport #{bits} bits" unless bits == 4096 or bits == 2048 puts "Generate #{bits} bits RSA keys" Crypto::create_keys( File.join(Dir.getwd, "rsa_key"), File.join(Dir.getwd, "rsa_key.pub"), bits ) puts "Done!" exit end if opts.local? try_create_dir opts[:local] @backup = Backup::Instance.new opts[:local] else [:key, :secret, :bucket].each do |arg| if opts[arg].nil? and @config.send(arg).nil? puts_fail "Argument '--#{arg}' should not be empty" end end @backup = Backup::Instance.new( "backups", true, :bucket => @config.bucket || opts[:bucket], :key => @config.key || opts[:key], :secret => @config.secret || opts[:secret] ) end hostname = @config.hostname || opts[:hostname] if opts.hostname? @backup.hostname = hostname unless hostname.nil? timeout = @config.timeout || opts[:timeout] if opts.timeout? @backup.file_item.timeout = timeout unless timeout.nil? compression = @config.compression || opts[:compression] if opts.compression? @backup.compression = compression unless compression.nil? if opts.list? jars_list = @backup.jars unless jars_list.empty? puts "List of jars:\n" jars_list.keys.sort.each do |key| puts " #{key.dark_green}: #{jars_list[key]}" end else puts "Nothing to listing." end exit end if !!@config.token || opts.token? key = @config.token || opts[:token] puts_fail "Key #{key.dark_green} not found" unless File.exists? key size = (@config.size || opts[:size]).to_i puts_fail "Unsupport #{size} bits" unless size == 4096 or size == 2048 @backup.rsa_key(key, size) end if opts.date? date = opts[:date].split("-") unless date.length == 1 @start_date = Backup::Timestamp.parse_timestamp date[0] @end_date = Backup::Timestamp.parse_timestamp date[1], true puts_fail "Last date less than start date" if start_date > end_date else @start_date = Backup::Timestamp.parse_timestamp date[0] @end_date = Backup::Timestamp.parse_timestamp date[0], true end else @start_date = nil @end_date = Time.now.utc end if opts.jar? opts[:jar].split(" ").each do |jar| versions = @backup.jar_versions(jar) unless versions.empty? puts "Versions of backup '#{jar}':" versions.each do |version| puts " => #{version.dark_green}: #{Backup::Timestamp.to_str(version)}" end else puts "Versions doesn't exists for jar: #{jar}" end end exit end if opts.rescue? paths = opts[:rescue].split(" ") jars_list = @backup.jars puts jars_list include_path = lambda {|path| jars_list.has_key?(path)} jars_hashes = paths.map do |path| unless path.length == 32 and path.match /[0-9a-f]{32}/ path = File.expand_path path unless include_path[path] or include_path["#{path}/"] puts_fail "Jar \"#{path}\" not exists." end jars_list[path] || jars_list["#{path}/"] else unless jars_list.has_value? path puts_fail "Jar with hash \"#{path}\" not exists." else path end end end if opts.to? @to = File.expand_path opts[:to] try_create_dir @to else @to = "/" end @index = {} jars_hashes.each do |hash| versions = @backup.jar_versions(hash) last_version = Backup::Timestamp.last_from(versions, @end_date, @start_date) unless last_version.nil? @index[hash] = last_version else error_path = "#{Backup::Jar.hash_to_path(@backup.file_item, @backup.root_path, hash)}" start_date = Backup::Timestamp.to_s(@start_date) end_date = Backup::Timestamp.to_s(@end_date) unless @start_date.nil? puts_fail "Nothing found for #{error_path}, between date: #{start_date} - #{end_date}" else puts_fail "Nothing found for #{error_path}, for date: #{end_date}" end end end @index.each do |hash, timestamp| @backup.restore_jar_to(hash, timestamp, @to) end puts "Done!".green exit end if !@config.paths.nil? or opts.add? if File.exists? "/var/tmp/encbs.swap" meta = YAML::load open("/var/tmp/encbs.swap").read jar_path, timestamp = meta[:jar_path], meta[:timestamp] dirs = @backup.file_item.dir File.expand_path("../", jar_path) if dirs.include? File.basename(jar_path) meta.delete :timestamp meta.delete :jar_path @backup.file_item.create_file_once( "#{jar_path}/#{timestamp}.yml", meta.to_yaml ) FileUtils.rm "/var/tmp/encbs.swap" end end if opts.add? paths = opts[:add].split(" ") else paths = @config.paths.split(" ") end paths = paths.map do |path| path = File.expand_path path puts_fail "Path \"#{path}\" not exists." unless File.exists? path path end paths.each do |path| unless opts.increment? purge = @config.purge || opts.purge? else purge = false end increment = @config.increment || opts.increment? @backup.create! path, increment, purge end puts "Done!".green end ensure remove_lock end