diff --git a/config/initializers/00_settings.rb b/config/initializers/00_settings.rb index d0ff3be..3515547 100644 --- a/config/initializers/00_settings.rb +++ b/config/initializers/00_settings.rb @@ -1,9 +1,11 @@ Archiving.settings director_name: YAML.load_file(Rails.root.join('config', 'bacula.yml'))[Rails.env]. symbolize_keys[:director] Archiving.settings vima_oauth_enabled: true Archiving.settings institutional_authentication_enabled: true Archiving.settings okeanos_authentication_enabled: false Archiving.settings default_sender: 'admin@archiving.grnet.gr' Archiving.settings admin_email: 'admin@archiving.grnet.gr' + +Archiving.settings temp_db_retention: 3.days diff --git a/lib/bvfs.rb b/lib/bvfs.rb index 16dd2e6..6c36d1e 100644 --- a/lib/bvfs.rb +++ b/lib/bvfs.rb @@ -1,133 +1,132 @@ 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 + # Issues the bvfs command for cleaning up a temporary db table + # + # @param dbname[String] the database table's name + def purge_db(dbname) + exec_command(pipe_to_bconsole(".bvfs_cleanup path=#{dbname}")) + 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 diff --git a/lib/tasks/bvfs_cleanup.rake b/lib/tasks/bvfs_cleanup.rake new file mode 100644 index 0000000..c0f4184 --- /dev/null +++ b/lib/tasks/bvfs_cleanup.rake @@ -0,0 +1,17 @@ +namespace :bvfs do + desc 'Cleans up the restore database' + task cleanup: :environment do + for_purge = ActiveRecord::Base.connection.tables.select do |name| + match_data = name.match(/^b2\d+(\d{12}$)/) + match_data.present? && + match_data[1].present? && + match_data[1] < (Archiving.settings[:temp_db_retention].ago.to_f * 100).to_i.to_s + end + + for_purge.each do |dbname| + Bvfs.new(nil,[]).purge_db(dbname) + end + + Rails.logger.warn("[BVFS]: Cleaned up dbs: #{for_purge.join(', ')}") + end +end