class SiteServerDbBackup include Mongoid::Document include Mongoid::Timestamps PeriodsTypes=['day','week','month'] belongs_to :site_server field :disable, type: Boolean, default: false field :backup_time, type: String, default: '03:00' field :path , type: String ,default: '/home/backup/db' field :period, type: Integer, default: 0 # 0 => daily , 1 => weekly , 2 => monthly field :retain_count, type: Integer, default: 7 field :need_rewrite, type: Boolean, default: true before_save do if self.changed? self.need_rewrite = true end end def to_crontab_script(return_string=true) # minute , hour, day(of month, 1~31), month(1~12), day(of week,0~6) crontab_time = ['*', '*', '*', '*', '*'] hour, minute = self.backup_time.split(':').map{|s| s.to_i} crontab_time[0] = minute.to_s rescue '0' crontab_time[1] = hour.to_s rescue '0' if self.period == 1 #weekly crontab_time[4] = '0' #every Sunday elsif self.period == 2 #monthly crontab_time[2] = '1' #day 1 of every month end if self.retain_count retain_text = "1 week ago" if self.period != 0 || self.retain_count != 7 retain_text = "#{self.retain_count} #{PeriodsTypes[self.period]} ago" end scripts = ["#{crontab_time.join(' ')} mongodump -o #{self.path}/`date \"+\\%Y\\%m\\%d\"`_db"] if hour < 23 next_hour = hour + 1 crontab_time[1] = next_hour.to_s else crontab_time[1] = ((hour + 1) % 24).to_s if self.period == 1 #weekly crontab_time[4] = '1' #every Sunday + 1 = Monday elsif self.period == 2 #monthly crontab_time[2] = '2' #day 1 of every month + 1 = 2 end retain_text += " 1 day ago" end scripts << "#{crontab_time.join(' ')} rm -fr #{self.path}/`date --date=\"#{retain_text}\" \"+\\%Y\\%m\\%d\"`_db" end if return_string scripts.join("\n") else scripts end end def self.read_from_crontab_line(crontab_line, crontab_lines) if crontab_line.include?('mongodump') tmp = crontab_line.split(/\s+[^\s]*mongodump\s+/) # ex: ["0 3 * * *", "-o /home/backup/db/`date \"+\\%Y\\%m\\%d\"`_db"] if tmp.count == 2 crontab_time = tmp[0].split(/\s+/) path = File.dirname(tmp[1].split('-o')[1].strip) rescue nil if path if crontab_time[4] != '*' #weekly period = 1 period_unit = 1.week elsif crontab_time[2] != '*' #monthly period = 2 period_unit = 1.month else #daily period = 0 period_unit = 1.day end time = "#{crontab_time[1].rjust(2, "0")}:#{crontab_time[0].rjust(2, "0")}" regex_path = /\s+#{::Regexp.escape(path)}\// match_line = crontab_lines.select{|l| l.match(/\s+(|\/usr\/bin\/)rm/) && l.match(regex_path)}.first if match_line.nil? retain_count = nil else retain_text = match_line.scan(/`\s*date\s+\-\-date=[\'\"]([^\'\"]+)[\'\"]/).flatten.first tmp_retain_count, tmp_period = retain_text.sub(/\s+ago/, '').split(/\s+/) tmp_retain_count = tmp_retain_count.to_i retain_count = (tmp_retain_count.send(tmp_period) / period_unit rescue nil) end return [time, path, period, retain_count] else return nil end else return nil end else return nil end end def self.clean_crontab_setting(crontab_lines_str) crontab_lines = crontab_lines_str.split("\n") related_path = [] crontab_lines.each do |crontab_line| if crontab_line.include?('mongodump') tmp = crontab_line.split(/\s+[^\s]*mongodump\s+/) # ex: ["0 3 * * *", "-o /home/backup/db/`date \"+\\%Y\\%m\\%d\"`_db"] output_dir = File.dirname(tmp[1].split('-o')[1].strip) rescue nil if output_dir related_path << output_dir end end end related_path_reg = Regexp.union(related_path.map{|s| /\s+#{::Regexp.escape(s)}\//}) crontab_lines_str = crontab_lines.map do |crontab_line| if crontab_line.match(related_path_reg) nil else crontab_line end end.compact.join("\n") end def self.write_crontab_setting(site_server, crontab_lines_str) new_crontab_lines = self.where(:site_server_id=> site_server.id, :disable=>false).map{|db_backup| db_backup.to_crontab_script(false)} crontab_lines = crontab_lines_str.split("\n") exists_indices = new_crontab_lines.map do |sub_crontab_lines| match_reg = ::Regexp.new(sub_crontab_lines[0].gsub(/\s+/, '\s+')) crontab_lines.index{|l| l.match(match_reg)} end removed_related_path = [] crontab_lines.each_with_index do |crontab_line, i| if crontab_line.include?('mongodump') && exists_indices.exclude?(i) tmp = crontab_line.split(/\s+[^\s]*mongodump\s+/) # ex: ["0 3 * * *", "-o /home/backup/db/`date \"+\\%Y\\%m\\%d\"`_db"] output_dir = File.dirname(tmp[1].split('-o')[1].strip) rescue nil if output_dir removed_related_path << output_dir end end end removed_related_path.each_with_index do |path| regex_path = /\s+#{::Regexp.escape(path)}\// crontab_lines = crontab_lines.select{|l| l.match(regex_path).nil?} end exists_indices.each_with_index do |idx, i| if idx.nil? crontab_lines << new_crontab_lines[i] end end crontab_lines_str = crontab_lines.compact.join("\n") end end