· 7 years ago · Mar 01, 2018, 12:18 AM
1#!/usr/bin/ruby
2
3require 'rubygems'
4require 'fileutils'
5require 'active_support'
6
7role :db, "192.168.2.2",
8 "192.168.3.2",
9 "192.168.4.2",
10 "192.168.5.2",
11 "192.168.7.2",
12 "192.168.9.2",
13 "192.168.10.2",
14 "192.168.11.2",
15 "192.168.12.2",
16 "192.168.13.2",
17 "192.168.14.2",
18 "192.168.15.2",
19 "192.168.16.2",
20 "192.168.17.2",
21 "192.168.18.2",
22 "192.168.19.2",
23 "192.168.20.2",
24 "192.168.21.2",
25 "192.168.22.2",
26 "192.168.23.2",
27 "192.168.24.2"
28
29# role :db, "192.168.1.12"
30
31set :user, "root"
32
33set :application, 'BTB'
34set :dbname, 'mysqladmin'
35set :dbpass, 'xxxxxxxxx'
36set :date, Time.now.strftime('%Y-%m-%d.%A')
37
38set :sync_script, '/usr/local/bin/sync_backups'
39set :sync_script_error_log, '/tmp/sync_backups.err'
40set :sync_times, '0 22,23,0,1,2,3 * * *' # runs a few times at night
41
42set :backup_script, '/usr/local/bin/run_backups'
43set :backup_script_error_log, '/tmp/run_backups.err'
44set :backup_mysql_times, '0 1 * * *'
45set :backup_btb_times, '5 1 * * *'
46
47# set :backup_server, '192.168.253.2' # zeus
48set :backup_server, '192.168.253.3' # mercury
49set :backup_folder, '/backups'
50set :crontab_file, '/etc/crontab'
51set :crontab_user, 'root ' # NOTE: This must be set to 'root ' (notice the space) ONLY if using /etc/crontab
52
53# All this method does is log into the remote host and dump the database out to the /backups folder
54desc "Backup all of the databases"
55task :request_backups, :roles => :db do
56 filename = "#{backup_folder}/#{application}_#{date}.sql.bz2"
57
58 on_rollback { delete filename }
59
60 run "mysqldump -u#{dbname} -p#{dbpass} BTB | bzip2 -c > #{filename}" do |ch, stream, out|
61 ch.send_data "#{dbpass}\n" if out =~ /^Enter password:/
62 end
63end
64
65# This task will ensure the mirrored folder is working on all of the remote hosts, by making
66# the folder and creating the script that calls the rsync backup command and add crontab entry
67desc "Installs the backup cron and backup script on all of the remote machines"
68task :install_backups, :roles => :db do
69 run "mkdir -p #{backup_folder}"
70
71 put "Put files here to be copied up to the master backup server. (currently mercury)", "#{backup_folder}/README"
72
73 # This script will exit out if it is already running
74 file = <<-FILE
75 #!/bin/bash
76
77 PID_FILE=/var/run/`basename $0`.pid
78 BACKUP_SERVER=#{backup_server}
79
80 if [ -f $PID_FILE ]
81 then
82 LAST_PID=`cat $PID_FILE`
83 if kill -0 $LAST_PID 2> /dev/null
84 then
85 echo "Already running ($LAST_PID)"
86 exit 0
87 else
88 echo $$ > $PID_FILE
89 fi
90 else
91 echo $$ > $PID_FILE
92 fi
93
94 LOCAL_SERVER=`grep -m 1 'address' /etc/network/interfaces | cut -d ' ' -f 2`
95 if [ $LOCAL_SERVER ]
96 then
97 rsync -az -e ssh $1 --delete --partial #{backup_folder}/ #{backup_server}:#{backup_folder}/$LOCAL_SERVER
98 else
99 echo "Couldn't determine IP address"
100 rm $PID_FILE
101 exit 1
102 fi
103
104 rm $PID_FILE
105 FILE
106
107 put file, sync_script, :mode => 700
108
109 file = <<-FILE
110 #!/bin/bash
111
112 mkdir -p /backups/$1/weekly
113 mkdir -p /backups/$1/monthly
114 mkdir -p /backups/$1/daily
115
116 BACKUP_FOLDER="/backups/$1"
117 DBLOGIN="#{dbname}"
118 DBPASS="#{dbpass}"
119
120 # This will take a weekly backup every monday, but will still do it on tuesday if it misses it on monday for some reason
121 if ls -l --time-style='+%s' $BACKUP_FOLDER/weekly/ | gawk '{if ($6 > last_modified) exit 1}' last_modified=`date +%s -d 'last monday 0:00'`
122 then
123 NEEDS_WEEKLY=true
124 else
125 NEEDS_WEEKLY=false
126 fi
127
128 # Same here, it will take a backup on the first of the month, and continue trying on consecutive days until one is made
129 if ls -l --time-style='+%s' $BACKUP_FOLDER/monthly/ | gawk '{if ($6 > last_modified) exit 1}' last_modified=`date +%s -d "$(( 10\#$(date +%d) - 1 )) days ago 0:00"`
130 then
131 NEEDS_MONTHLY=true
132 else
133 NEEDS_MONTHLY=false
134 fi
135
136 MONTHLY_FILENAME="$1_`date '+%Y-%m-%d.%b'`.sql.bz2"
137 WEEKLY_FILENAME="$1_`date '+%Y-%m-%d.%V'`.sql.bz2"
138 DAILY_FILENAME="$1_`date '+%Y-%m-%d.%A'`.sql.bz2"
139
140 MYSQL_DUMP="mysqldump -u$DBLOGIN -p$DBPASS $1"
141
142 if $NEEDS_MONTHLY && $NEEDS_WEEKLY; then
143 # Put the real file in monthly, link to in weekly and daily
144 cd $BACKUP_FOLDER/monthly
145 $MYSQL_DUMP | bzip2 -c > $MONTHLY_FILENAME
146 cd $BACKUP_FOLDER/weekly
147 ln -s ../monthly/$MONTHLY_FILENAME ./$WEEKLY_FILENAME
148 cd $BACKUP_FOLDER/daily
149 ln -s ../monthly/$MONTHLY_FILENAME ./$DAILY_FILENAME
150 elif $NEEDS_MONTHLY; then
151 # Put the real file in monthly, link to in daily
152 cd $BACKUP_FOLDER/monthly
153 $MYSQL_DUMP | bzip2 -c > $MONTHLY_FILENAME
154 cd $BACKUP_FOLDER/daily
155 ln -s ../monthly/$MONTHLY_FILENAME ./$DAILY_FILENAME
156 elif $NEEDS_WEEKLY; then
157 # Put the real file in weekly, link to in daily
158 cd $BACKUP_FOLDER/weekly
159 $MYSQL_DUMP | bzip2 -c > $WEEKLY_FILENAME
160 cd $BACKUP_FOLDER/daily
161 ln -s ../weekly/$WEEKLY_FILENAME ./$DAILY_FILENAME
162 else
163 # Put the real file in daily
164 cd $BACKUP_FOLDER/daily
165 $MYSQL_DUMP | bzip2 -c > $DAILY_FILENAME
166 fi
167
168 # delete old files
169 # 1 year ago
170 find $BACKUP_FOLDER/monthly -daystart -mtime +365 -exec rm {} \\;
171 # 1 month ago
172 find $BACKUP_FOLDER/weekly -daystart -mtime +31 -exec rm {} \\;
173 # 7 days ago
174 find $BACKUP_FOLDER/daily -daystart -mtime +7 -exec rm {} \\;
175 FILE
176
177 put file, backup_script, :mode => 700
178
179 run <<-CMD
180 echo "#{sync_times} #{crontab_user}#{sync_script} > #{sync_script_error_log} 2>&1" >> #{crontab_file};
181 echo "#{backup_btb_times} #{crontab_user}#{backup_script} BTB >> #{backup_script_error_log} 2>&1" >> #{crontab_file};
182 echo "#{backup_mysql_times} #{crontab_user}#{backup_script} mysql >> #{backup_script_error_log} 2>&1" >> #{crontab_file}
183 CMD
184
185 # TODO: should also have a script that cleans out old backups on the remote machines
186end
187
188# This will disable syncing with the master server, backups may still be "requested" but no upload will occur
189task :disable_backups, :roles => :db do
190 sync_script_file = sync_script.match(/[a-z\._]+$/)[0] # avoids backslashes
191 backup_script_file = backup_script.match(/[a-z\._]+$/)[0] # avoids backslashes
192 run <<-CMD
193 sed -i -e '/^.*#{sync_script_file}.*$/d' #{crontab_file};
194 sed -i -e '/^.*#{backup_script_file}.*$/d' #{crontab_file}
195 CMD
196end
197
198# Add's syncing to master server
199task :enable_backups, :roles => :db do
200 run <<-CMD
201 echo "#{sync_times} #{crontab_user}#{sync_script} > #{sync_script_error_log} 2>&1" >> #{crontab_file};
202 echo "#{backup_btb_times} #{crontab_user}#{backup_script} BTB >> #{backup_script_error_log} 2>&1" >> #{crontab_file};
203 echo "#{backup_mysql_times} #{crontab_user}#{backup_script} mysql >> #{backup_script_error_log} 2>&1" >> #{crontab_file}
204 CMD
205end