f6559f9b692294b401244f7dc65eb47c203a8779
[matthijs/projects/backupninja.git] / src / lib / backupninja / handlers / __init__.py
1 #
2 #    Backupninja python reimplementation, based on original backupninja program
3 #    by riseup.net.
4 #    Copyright (C) 2010  Matthijs Kooijman <matthijs@stdin.nl>
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 """ Action superclass with common functionality """
21
22 import sys, ConfigParser
23 import logging as log
24
25 from backupninja import config
26
27 class Action(object):
28     """
29     Subclasses of Action represent handlers for various action types.
30     This class is called Action instead of Handler, since even though the
31     classes could be referred to as handlers, the instances of this
32     class are really actions (i.e., it represents a specific action,
33     which is a combination of a action type and a specific action
34     configuration).
35     """
36     def __init__(self):
37         # Subclasses should overwrite this with their default config
38         # See backupninja.config.load_config for the structure of this
39         # value.
40         self.default_config = {}
41
42     def run(self, **kwargs):
43         """
44         Run this action for a single target. Override this method
45         in a subclass
46         """
47         pass
48
49     def finish(self, **kwargs):
50         """
51         Called when all targets have been processed. Can be overridden
52         in a subclass.
53         """
54         pass
55
56     def load_config(self, filename):
57         """
58         Load the configuration for this action from the given filename.
59         """
60         self.conf = config.load_config(filename, self.default_config)
61
62     def get_config_optional(self, section, option):
63         """
64         Returns the value of the given option. If the option was not set
65         (and no default was set in self.default_config), return None.
66
67         This is a convenience wrapper for ConfigParser.get(), since that
68         throws an exception on unset options.
69         """
70         try:
71             return self.conf.get(section, option)
72         except ConfigParser.NoOptionError:
73             return None
74
75     def get_config_mandatory(self, section, option):
76         """
77         Returns the value of the given option. If the option was not set
78         (and no default was set in self.default_config), raises a
79         backupninja.config.ConfigError.
80
81         This is a convenience wrapper for ConfigParser.get(), since that
82         has a very generic exception message on unknown options.
83         """
84         try:
85             return self.conf.get(section, option)
86         except ConfigParser.NoOptionError:
87             raise config.ConfigError("Option '%s' in section '%s' is mandatory, please configure it" % (option, section))
88
89 def create_action(ty):
90     """
91     Create a new (subclass of) Action object for an action with the
92     given type.
93
94     If the handler class for this type cannot be loaded, an exception is
95     thrown.
96     """
97     modname = 'backupninja.handlers.%s' % ty
98     # Load the handler if it is not loaded yet
99     if not modname in sys.modules:
100         log.debug('Loading handler for type "%s"', ty)
101         try:
102             __import__(modname, globals(), locals(), [])
103         except ImportError, e:
104             # Add some extra info, since the default exception does not
105             # show the full module name.
106             raise ImportError('Cannot load module %s: %s' % (modname, e))
107         log.debug('Loaded handler for type "%s" from "%s"', ty, sys.modules[modname].__file__)
108     # Get the module from the module table
109     module = sys.modules[modname]
110
111     # Check that the module has a "handler" top level function, which
112     # should create a new Action object.
113     if not hasattr(module, 'handler'):
114         raise ImportError('%s is not valid: it '
115                           'does not have a "handler" top level function.' 
116                           % (module.__file__))
117
118     # Call the "handler" function to create the actual action
119     action = module.handler()
120    
121     # Check if the handler returned is really a subclass of Action
122     if not isinstance(action, Action):
123         raise TypeError('%s is not valid, %s.handler did not return a '
124                         'subclass of backupninja.handlers.Handler.'
125                         % (module.__file__, modname))
126     return action