Script: Run rsnapshot backups only once and rollback failed backups using rsnapshot-once
I use rsnapshot to backup all of my data to my HTPC and home server (the home partition, office documents and the root file system). While rsnapshot is not as shiny as other backup tools, it is very flexible and effective: rsnapshot is based on rsync and makes hardlink-based backups (like cp -al), i.e. backups that point to the same inode on the disk if a file in consecutive backups is identical (much like SIS in deduplication).
However, rsnapshot is meant to be triggered by cronjobs and is built for always-on server machines rather than for lid-open-lid-close-type machines like laptops: That means that rsnapshot must be scheduled to run at a certain time (no retries!) and is not prone sudden system shutdowns. Furthermore, it does not detect failures and simply leaves unfinished backups as if they were complete. That in turn leads to more disk space being used for the backups, because the last complete backup is not really complete.
I wrote a little helper script to fix exactly this behavior: rsnapshot-once makes sure that (1) rsnapshot is only called if a backup is necessary (once every 24h for ‘daily’, once ever 7 days for ‘weekly’, …) even if rsnapshot-once is called multiple times, and (2) that crashed/interrupted backup runs are rolled-back before starting a new backup run.
Contents
1. What is rsnapshot-once?
rsnapshot-once is a wrapper for rsnapshot to ensure that daily, weekly and monthly tasks are run only once in the respective time period, i.e. it ensures that ‘weekly’ backups are executed only once a week, regardless how often rsnapshot-once is called.
rsnapshot-once accepts the same parameters as rsnapshot and uses the same config file. No additional configuration is needed.
So instead of running something like this:
1 |
rsnapshot -c /etc/rsnapshot.home.conf daily |
You would rather run this:
1 |
rsnapshot-once -c /etc/rsnapshot.home.conf daily |
Similarly, simply replace rsnapshot by rsnapshot-once in the crontab, if you run backups regularly as a cronjob. Instead of this:
1 2 |
# Hope that your computer is on at 10am 0 10 * * * rsnapshot -c /etc/rsnapshot.home.conf daily |
Write this:
1 2 |
# daily (try every full hour!) 0 * * * * rsnapshot-once -c /etc/rsnapshot.home.conf daily |
2. What’s the difference?
There are a couple of things that rsnapshot-once adds to the regular rsnapshot-behavior:
- Run multiple times: For the intervals ‘daily’, ‘weekly’ and ‘monthly’, rsnapshot-once will first check the timestamp of the last successful backup (daily.0, weekly.0 or monthly.0) before running rsnapshot. So rsnapshot-once will only call rsnapshot if the timestamp of the ‘daily.0’ directory is more than 24 hours old.
- Rollbacks of failed backups: Before running rsnapshot, rsnapshot-once checks whether the last backup was complete. If it wasn’t, the last directory (e.g. daily.0) is deleted and consecutive directories are renamed (daily.1 -> daily.0, …). rsnapshot-once uses its own pidfile to check if a previous backup run has been interrupted.
- 15 minutes after boot/standby: To make sure that a backup is not starting right after the boot process, rsnapshot-once checks the uptime and the resume time before running rsnapshot. Only if both are greater than 15 minutes, rsnapshot is called.
3. Installation
Simply download rsnapshot-once, place it in your local bin directory (e.g. /usr/local/bin) and make it executable. If you haven’t already, install the PHP command line interpreter. Once this is done, it can be called from the command line or in cronjobs:
1 2 3 |
sudo apt-get install php5-cli wget -O /usr/local/bin/rsnapshot-once http://blog.philippheckel.com/uploads/2013/06/rsnapshot-once chmod +x /usr/local/bin/rsnapshot-once |
4. Example Usage
I use rsnapshot and rsnapshot-once for backing up the home-partition (/home), the root partition (/) and my office documents (/home/user/Office). All of them are backed up weekly and monthly, but the office documents are additionally backed up daily (because they change more often).
I set up my cronjobs to run rsnapshot-once like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# DAILY # Try a couple of times a night, 8-11pm 45 21,22,23 * * * rsnapshot-once -c /etc/rsnapshot.office.conf daily # WEEKLY # Try for 3 consecutive days, a couple of times a night, Mon-Wed 8-11pm 0 20,21,22,23 * * 1,2,3 rsnapshot-once -c /etc/rsnapshot.office.conf weekly 15 20,21,22,23 * * 1,2,3 rsnapshot-once -c /etc/rsnapshot.root.conf weekly 30 21,21,22,23 * * 1,2,3 rsnapshot-once -c /etc/rsnapshot.home.conf weekly # MONTHLY # Try on 4 consecutive days, a couple of times a night, 1st-4th of each month 59 22,23 1,2,3,4 * * rsnapshot-once -c /etc/rsnapshot.office.conf monthly 58 21,22 1,2,3,4 * * rsnapshot-once -c /etc/rsnapshot.root.conf monthly 57 20,21 1,2,3,4 * * rsnapshot-once -c /etc/rsnapshot.home.conf monthly |
First/any run: When rsnapshot-once is run, it writes to the same log file as rsnapshot (if defined in the config file). The output of a successful run for my daily office documents looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[23:42:57] ## STARTING BACKUP ###################### [23:42:57] $ rsnapshot-once '-c' '/etc/rsnapshot.office.conf' 'daily' [23:42:57] Config read from: /etc/rsnapshot.office.conf [23:42:57] - logfile = /var/log/rsnapshot.office.log [23:42:57] - snapshot_root = /backups/office/ [23:42:57] Checking rsnapshot-once pidfile at /backups/office/.rsnapshot-once.pid ... Does not exist. Last backup was clean. [23:42:57] Checking delays (minimum 15 minutes since startup/wakeup) ... [23:42:57] - Computer uptime is 387.5 minutes. THAT'S OKAY. [23:42:57] - Computer resume time is 48.0 minutes. THAT'S OKAY. [23:42:57] Newest backup for 'daily' at /backups/office/daily.0 was at 27/Jun/2013, 23:42:53. [23:42:57] Last run is 24.0 hour(s) ago (min. is 23 hours). [23:42:57] Writing rsnapshot-once pidfile (PID 14469) to /backups/office/.rsnapshot-once.pid. [23:42:57] NOW RUNNING JOB: rsnapshot '-c' '/etc/rsnapshot.office.conf' 'daily' 2>&1 [23:42:58] /usr/bin/rsnapshot -c /etc/rsnapshot.office.conf daily: started [23:42:58] echo 14486 > /var/run/rsnapshot.pid [23:42:58] /bin/rm -rf /backups/office/daily.6/ [23:43:10] mv /backups/office/daily.5/ /backups/office/daily.6/ [23:43:10] mv /backups/office/daily.4/ /backups/office/daily.5/ [23:43:10] mv /backups/office/daily.3/ /backups/office/daily.4/ [23:43:10] mv /backups/office/daily.2/ /backups/office/daily.3/ [23:43:10] mv /backups/office/daily.1/ /backups/office/daily.2/ [23:43:10] /bin/cp -al /backups/office/daily.0 /backups/office/daily.1 [23:43:21] /usr/bin/rsync -ax --delete --numeric-ids --relative --delete-excluded /home/user/Office /backups/office/daily.0/office/ [23:43:44] touch /backups/office/daily.0/ [23:43:44] rm -f /var/run/rsnapshot.pid [23:43:44] /usr/bin/rsnapshot -c /etc/rsnapshot.office.conf daily: completed successfully [23:43:44] Removing rsnapshot-once pidfile at /backups/office/.rsnapshot-once.pid (CLEAN EXIT). [23:43:44] Rotating log ... [23:43:44] ## BACKUP COMPLETE ###################### |
Duplicate run: If the same command is again right after this backup, rsnapshot will not be called, because the las successful backup was less than 24h ago:
1 2 3 4 5 6 7 8 9 10 11 12 |
[23:47:02] ## STARTING BACKUP ###################### [23:47:02] $ rsnapshot-once '-c' '/etc/rsnapshot.office.conf' 'daily' [23:47:02] Config read from: /etc/rsnapshot.office.conf [23:47:02] - logfile = /var/log/rsnapshot.office.log [23:47:02] - snapshot_root = /backups/office/ [23:47:02] Checking rsnapshot-once pidfile at /backups/office/.rsnapshot-once.pid ... Does not exist. Last backup was clean. [23:47:02] Checking delays (minimum 15 minutes since startup/wakeup) ... [23:47:02] - Computer uptime is 391.6 minutes. THAT'S OKAY. [23:47:02] - Computer resume time is 52.1 minutes. THAT'S OKAY. [23:47:02] Newest backup for 'daily' at /backups/office/daily.0 was at 28/Jun/2013, 23:43:44. [23:47:02] Job does NOT need to run. Last run is only 0.1 hour(s) ago (min. is 23 hours). EXITING. [23:47:02] ## BACKUP ABORTED ####################### |
Rollback run after interrupted backup: If the command is run after a failed or interrupted backup (e.g. due to a system shutdown), the output looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
[00:01:53] ## STARTING BACKUP ###################### [00:01:53] $ rsnapshot-once '-c' '/etc/rsnapshot.office.conf' 'daily' [00:01:53] Config read from: /etc/rsnapshot.office.conf [00:01:53] - logfile = /var/log/rsnapshot.office.log [00:01:53] - snapshot_root = /backups/office/ [00:01:53] Checking rsnapshot-once pidfile at /backups/office/.rsnapshot-once.pid ... Exists. PID 14678 not running. Script crashed before. [00:01:53] Cleaning up unfinished backup ... [00:01:53] - Deleting /backups/office/daily.0 ... DONE [00:02:00] - Moving /backups/office/daily.1 to /backups/office/daily.0 ... DONE [00:02:00] - Moving /backups/office/daily.2 to /backups/office/daily.1 ... DONE [00:02:00] - Moving /backups/office/daily.3 to /backups/office/daily.2 ... DONE [00:02:00] - Moving /backups/office/daily.4 to /backups/office/daily.3 ... DONE [00:02:00] - Moving /backups/office/daily.5 to /backups/office/daily.4 ... DONE [00:02:00] - Moving /backups/office/daily.6 to /backups/office/daily.5 ... DONE [00:02:00] Checking delays (minimum 15 minutes since startup/wakeup) ... [00:02:00] - Computer uptime is 406.6 minutes. THAT'S OKAY. [00:02:00] - Computer resume time is 67.0 minutes. THAT'S OKAY. [00:02:00] Newest backup for 'daily' at /backups/office/daily.0 was at 27/Jun/2013, 23:50:53. [00:02:00] Last run is 24.2 hour(s) ago (min. is 23 hours). [00:02:00] Writing rsnapshot-once pidfile (PID 14782) to /backups/office/.rsnapshot-once.pid. [00:02:00] NOW RUNNING JOB: rsnapshot '-c' '/etc/rsnapshot.office.conf' 'daily' 2>&1 [00:02:10] Removing rsnapshot-once pidfile at /backups/office/.rsnapshot-once.pid (CLEAN EXIT). [00:02:10] Rotating log ... [00:02:11] ## BACKUP COMPLETE ###################### |
Hi, looks like a perfect script for my use. But, before I have used sync_first and sync before rotating – Is this not needed with this script?
Great script. I always use rsnapshot but incomplete/failed backups were always a problem.
Hi,
A fu**ing great script, tested and adopted.
Using rsnapshot to to do incremental backup on local station that’s not always on. rsnapshot-once plainly answers my need to get scheduled rsnapshot backups to be run, as well as to revert in case the process was interrupted (because eg storage was full). I just needed some more configuration:
In php.ini:
open_basedir = …:/etc/rsnapshot.conf:/var/log/rsnapshot:/PATH_to_SNAPSHOT_ROOT
[Date]
date.timezone = “Europe/Paris”
date.default_latitude = NN.NNNN
date.default_longitude = NN.NNNN
Add full path to the executable in crontab (using cronie):
/usr/local/bin/rsnapshot-once -c …
Many thanks for sharing Philipp. Now what about the future? Or is it a dev-once ;-} Any chance to pull your great rsnapshot-once script on eg, Github?
PS: forgot to say. Used to execute rsnapshot’s
cmd_preexec
before running the scheduled backup, eg to mount/umount the backup drive. This particular case is not as easy with rsnapshot-once, which needs the snapshot_root path to be readable before launching rsnapshot.I quickly created a Github repo here — pull against that if you have additions/suggestions: https://github.com/binwiederhier/rsnapshot-once
How could I get this to work with rsnapshot report functionality? I would like to combine this wrapper with the reporting function to get a mail every day (once, e.g. end of day) to know how things are going. Any ideas? Maybe I have to add another cron job (daily) to pipe the logfile to rsnapshot report perl script and then pipe to mail? Will this wrapper not mess with the report?
I’ve noticed a nasty bug in this script…
In cron you define the “weekly” to run a couple of times a week. This screws up my weeklies.
drwxr-xr-x 5 root root 4,0K 26 mei 20:38 weekly.0/
drwxr-xr-x 5 root root 4,0K 25 mei 21:11 weekly.1/
drwxr-xr-x 5 root root 4,0K 24 mei 20:38 weekly.2/
drwxr-xr-x 5 root root 4,0K 21 mei 03:00 weekly.3/
As you can see I have weeklies every day… that shouldn’t be right?
I also have another cycle running for a second computer.
drwxr-xr-x 5 root root 4,0K 2 jun 08:45 daily.0/
drwxr-xr-x 5 root root 4,0K 1 jun 08:45 daily.1/
drwxr-xr-x 5 root root 4,0K 31 mei 08:51 daily.2/
drwxr-xr-x 5 root root 4,0K 30 mei 08:45 daily.3/
drwxr-xr-x 5 root root 4,0K 29 mei 08:45 daily.4/
drwxr-xr-x 5 root root 4,0K 28 mei 08:51 daily.5/
drwxr-xr-x 5 root root 4,0K 26 mei 17:08 weekly.3/
What’s with that??? Why does the weekly go to three? Isn’t it because it’s trying to cycle multiple times?
That’s a problem that rsnapshot has, not my tiny wrapper.
PHP 5.6.17 (cli) on centos 6.5
I get this warning:
Warning: file_put_contents( /mnt/rsnapshot/files/rsnapshot.log): failed to open stream: No such file or directory in /usr/local/bin/rsnapshot-once on line 299
The file exists 100%.
Any idea ?
regards
Have been using rsnapshot-once since my comment above to backup three boxes to an external HDD plugged in my Arch desktop (push from the desktop powered by Arch linux). No issue at all on this bleeding edge system!
Am now switching to OpenMediaVault, a diy NAS based on Debian Wheezy. rsnapshot-once also works fine. Produces a log (and email) for each (attempted) backup, but I’ll see what I can do to lighten the “spams” burden.
Hello, I am getting the same issue as Masi-O running your script on a OMV raspberry pi system with PHP 5.4.45-0+deb7u5.
Here is my warning message:
PHP Warning: file_put_contents( /var/log/rsnapshot.log): failed to open stream: No such file or directory in /usr/local/bin/rsnapshot-once on line 299
Not only does the file /var/log/rsnapshot.log exist, but if I delete it running rsnapshot-once will create a new one.
Second issue I am experiencing: I want to run backups from a laptop that isn’t always online, so when it is offline I get an error but the backup will complete successfully. After I turn on my laptop and run rsnapshot-once again it wont rollback the backup as he sees that it was successfull (but empty). Any suggestions?
FIXED ERROR:
PHP Warning: file_put_contents( /path/to/backup.log): failed to open stream: No such file or directory in rsnapshot-once.php …
Tooked 3 hours to find this bug…there is extra space by opening file_put_contents
https://github.com/grambas/rsnapshot-once/blob/master/rsnapshot-once
I ported your script to python and added some things like recursive config file parsing when using include_config or checking for sync_first as this present could break your rsnapshot environment when rsnapshot-once is invoked. I also added a hourly option with an optional inteval argument. Defaults to every 4 hours. You can get it on github: https://github.com/devjb/rsnapshot-scripts feel free to add improvements by pull requests. I hacked this quickly and it is far away from being really beautiful code. But it looks like it works and I needed something asap ;-)
I ported the script to python and adjusted it to my needs. That includes for example catching of “sync_first” (not supported, but does not break things when set), nested include files and stuff like that. Grab it from Github:
https://github.com/devjb/rsnapshot-scripts