First step towards a new, improved cumulus front-end.
[cumulus.git] / python / cumulus / config.py
1 # Cumulus: Smart Filesystem Backup to Dumb Servers
2 #
3 # Copyright (C) 2012  Google Inc.
4 # Written by Michael Vrable <mvrable@cs.ucsd.edu>
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with this program; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 """Parsing of Cumulus backup configuration files.
21
22 See the Cumulus documentation for a description of the configuration file
23 format.
24 """
25
26 import ConfigParser
27 import datetime
28 import re
29
30 from cumulus import retention
31
32 _BACKUP_PREFIX = "backup:"
33 _TIME_UNITS = {"s": 1, "m": 60, "h": 3600, "D": 86400, "W": 7 * 86400,
34                "M": 30 * 86400, "Y": 365 * 86400}
35 _INTERVAL_RE = r"(\d+)([smhDWMY])"
36
37 def _build_retention_engine(spec):
38     """Parse a retention specification and return a RetentionEngine object."""
39     policy = retention.RetentionEngine()
40     class_re = re.compile(r"^(\w+):((%s)+)$" % _INTERVAL_RE)
41     interval_re = re.compile(r"^%s(.*)$" % _INTERVAL_RE)
42     for s in spec.split():
43         m = class_re.match(s)
44         if not m:
45             print "Invalid retain spec:", s
46             continue
47         period = datetime.timedelta()
48         classname = m.group(1)
49         intervalspec = m.group(2)
50         while intervalspec:
51             m = interval_re.match(intervalspec)
52             seconds = int(m.group(1)) * _TIME_UNITS[m.group(2)]
53             period = period + datetime.timedelta(seconds=seconds)
54             intervalspec = m.group(3)
55         print classname, period
56         policy.add_policy(classname, period)
57     return policy
58
59
60 class CumulusConfig(object):
61     def __init__(self, filename):
62         """Parse a Cumulus backup configuration from the specified file."""
63         self._config = ConfigParser.RawConfigParser()
64         self._config.readfp(open(filename))
65
66     def get_global(self, key):
67         return self._config.get("global", key)
68
69     def backup_schemes(self):
70         """Returns a list of backup schemes."""
71         return [s[len(_BACKUP_PREFIX):] for s in self._config.sections()
72                 if s.startswith(_BACKUP_PREFIX)]
73
74     def get_retention_for_scheme(self, scheme):
75         spec = self._config.get(_BACKUP_PREFIX + scheme, "retain")
76         return _build_retention_engine(spec)