diff --git a/lib/bvfs.rb b/lib/bvfs.rb new file mode 100644 index 0000000..16dd2e6 --- /dev/null +++ b/lib/bvfs.rb @@ -0,0 +1,133 @@ +class Bvfs + attr_accessor :client, :jobids, :files, :dirs + + def initialize(client, jobids) + @jobids = jobids.join(',') + @client = client + end + + # Fetches the directories that exist in the given directory and + # stores the output to the result instance variable + # + # @param pathid[String|Integer] If nil or omitted, root directory is implied + def fetch_dirs(pathid=nil) + path = pathid.nil? ? 'path=\"\"':"pathid=#{pathid}" + command = pipe_to_bconsole(".bvfs_lsdirs jobid=#{jobids} #{path}") + @dirs = exec_command(command) + end + + # Fetches the files that exist in the given directory and + # stores the output to the result instance variable + # + # @param pathid[String|Integer] If nil or omitted, root directory is implied + def fetch_files(pathid=nil) + path = pathid.nil? ? 'path=\"\"':"pathid=#{pathid}" + command = pipe_to_bconsole(".bvfs_lsfiles jobid=#{jobids} #{path}") + @files = exec_command(command) + end + + # Extracts the id and name of the bvfs_lsdirs command + def extract_dir_id_and_name + dirs. + split("\n"). + select { |x| x[/^(\d+\W){4}.*[^.]/] }. + map {|x| s = x.split("\t"); [s.first, s.last.gsub(/(.)\/$/, '\\1')] }. + select { |x| !['.', '..'].include?(x.last) }. + to_h + end + + # Extracts the id and name of the bvfs_lsfiles command + def extract_file_id_and_name + files. + split("\n"). + select { |x| x[/^(\d+\W){4}.*[^.]/] }. + map {|x| s = x.split("\t"); [s.third, s.last] }. + select { |x| !['.', '..'].include?(x.last) }. + to_h + end + + # Updates the bvfs cache for the specific job ids. + # This can take some time. Always provide a job id. + def update_cache + command = pipe_to_bconsole(".bvfs_update jobid=#{jobids}") + exec_command(command) + end + + # Handles restore of multiple selected files and directories + # + # * creates a db table with the needed files + # * issues the restore + # * cleans up the table + # + # @param file_ids[Array] the file ids that will be restored + # @param location[String] the client's restore location + # @param dir_ids[Array] the directory ids that will be restored + def restore_selected_files(file_ids, location = nil, dir_ids = nil) + location ||= '/tmp/bacula_restore/' + dir_ids ||= [] + + dbname = "b2#{client.id}#{(Time.now.to_f * 100).to_i}" + + shell_command = [ + create_restore_db(dbname, file_ids, dir_ids), + restore_command(dbname, location), + clear_cache + ].map { |command| pipe_to_bconsole(command) }.join(' && ') + + Rails.logger.warn("[BVFS]: #{shell_command}") + pid = spawn shell_command + Process.detach(pid) + end + + private + + # Generates the bvfs command needed in order to create a temporary database + # that will hold the files that we want to restore. + # + # @param file_ids[Array] the file ids that will be restored + # @param dir_ids[Array] the directory ids that will be restored + # + # @return [String] bvfs restore command + def create_restore_db(dbname, file_ids, dir_ids) + params = "jobid=#{jobids} path=#{dbname}" + params << " fileid=#{file_ids.join(',')}" if file_ids.any? + params << " dirid=#{dir_ids.join(',')}" if dir_ids.any? + + ".bvfs_restore #{params}" + end + + # Generates the restore command + # + # @param dbname[String] the name of the db table that has the desired files + # @param location[String] the client's restore location + # + # @return [String] bconsole's restore command + def restore_command(dbname, location) + "restore file=?#{dbname} client=\\\"#{client.name}\\\" where=\\\"#{location}\\\" yes" + end + + # Generates the bvfs command for cleaning up the temporary db table + # + # @param dbname[String] the database table's name + # @return [String] the bvfs command + def purge_db(dbname) + ".bvfs_cleanup path=#{dbname}" + end + + def clear_cache + '.bvfs_clear_cache yes' + end + + def exec_command(command) + Rails.logger.warn("[BVFS]: #{command}") + `#{command}` + end + + def pipe_to_bconsole(what) + "echo \"#{what}\" | #{bconsole}" + end + + def bconsole + "bconsole -c #{Rails.root}/config/bconsole.conf" + end +end