145 lines
5.6 KiB
Ruby
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 |