client_management/app/models/site_server_db_backup.rb

145 lines
5.6 KiB
Ruby

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
unless @skip_callback
if self.changed?
self.need_rewrite = true
end
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