]>
git.frykholm.com Git - butterbackup.git/blob - butterbackup.py
26822276a29d6449bb03069493c3be4d85ec498e
4 from subprocess
import check_call
, CalledProcessError
10 def __init__(self
, name
, config
):
13 if not self
.config
.has_section('host'):
14 self
.config
.add_section('host')
15 self
.store_dir
= self
.config
['host']['store_dir']
16 self
.host_dir
= os
.path
.join(self
.store_dir
, name
)
17 self
.subvol_dir
= os
.path
.join(self
.host_dir
, "latest")
18 self
.keep
= int(self
.config
.get("host", "keep", fallback
=-1))
21 if not os
.path
.exists(self
.host_dir
):
22 print("New host",self
.name
,".")
23 os
.makedirs(self
.host_dir
)
24 if not os
.path
.exists(self
.subvol_dir
):
26 check_call(shlex
.split("btrfs subvol create %s"% self
.subvol_dir
))
27 except CalledProcessError
as ex
:
28 print("Failed to create subvol! Aborting backup.")
31 command
= ("rsync -a --acls --xattrs --whole-file --numeric-ids --delete --delete-excluded --human-readable --inplace ")
32 excludes
= " --exclude " + " --exclude ".join(self
.config
.get("host", "exclude").split(',')) #FIXME
34 print(command
+ excludes
+ " root@%s:/ "%(self
.name
) + self
.subvol_dir
)
35 check_call(shlex
.split(command
+ excludes
+ " root@%s:/ "%(self
.name
) + self
.subvol_dir
))
36 except CalledProcessError
as ex
:
37 if ex
.returncode
in (24,):
40 print("Rsync error from %s, skipping snapshot. Rsync exit value=%s"%(self
.name
, ex
.returncode
))
42 todays_date
= datetime
.datetime
.now().date().strftime("%F")
43 if os
.path
.exists(os
.path
.join(self
.host_dir
, todays_date
)):
44 #There is a snapshot for today, removing it and creating a new one
46 check_call(shlex
.split("btrfs subvol delete %s"%(os
.path
.join(self
.host_dir
, todays_date
))))
47 except CalledProcessError
as ex
:
50 check_call(shlex
.split("btrfs subvol snapshot -r %s %s"%(self
.subvol_dir
,os
.path
.join(self
.host_dir
, todays_date
))))
51 except CalledProcessError
as ex
:
54 def prune_snapshots(self
):
56 print("No keep specified for %s, keeping all"%self
.name
)
58 if not os
.path
.exists(self
.host_dir
):
59 print("New host, no pruning needed")
61 snaps
= sorted([snap
for snap
in os
.listdir(self
.host_dir
) if not snap
== "latest" ], reverse
=True)
62 while len(snaps
) > self
.keep
:
65 check_call(shlex
.split("btrfs subvol delete %s"%(os
.path
.join(self
.host_dir
, snap
))))
66 except CalledProcessError
as ex
:
70 def __init__(self
, config_dir
):
71 self
.config_dir
= config_dir
72 if not os
.path
.exists(self
.config_dir
):
73 print("No config found", self
.config_dir
)
76 def run(self
, hostlist
=None):
77 self
.hosts
= hostlist
or os
.listdir(self
.config_dir
)
79 for host
in self
.hosts
:
80 if host
== 'default.cfg':
83 configfile
= os
.path
.join(self
.config_dir
, host
)
85 if not os
.path
.exists(configfile
):
86 # Trigger logging in the except clause
89 config
= configparser
.ConfigParser(strict
=False)
90 config
.read_file(open(os
.path
.join(self
.config_dir
, 'default.cfg'),'r'))
91 config
.read(configfile
)
92 except BaseException
as ex
:
93 print("Config error for %s. Skipping host."%host
)
95 h
= Host(host
, config
)
99 if __name__
== "__main__":
100 if os
.geteuid() != 0:
101 print("You need to be root. Otherwise all permissions will be lost.")
103 br
= BackupRunner("/etc/butterbackup")
105 hostlist
= sys
.argv
[1:]
106 br
.run(hostlist
=hostlist
)