| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: iso-8859-1 -*-
2 # vim: set ft=python ts=3 sw=3 expandtab:
3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
4 #
5 # C E D A R
6 # S O L U T I O N S "Software done right."
7 # S O F T W A R E
8 #
9 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
10 #
11 # Copyright (c) 2004-2007 Kenneth J. Pronovici.
12 # All rights reserved.
13 #
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License,
16 # Version 2, as published by the Free Software Foundation.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 #
22 # Copies of the GNU General Public License are available from
23 # the Free Software Foundation website, http://www.gnu.org/.
24 #
25 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
26 #
27 # Author : Kenneth J. Pronovici <pronovic@ieee.org>
28 # Language : Python (>= 2.3)
29 # Project : Cedar Backup, release 2
30 # Revision : $Id: stage.py 807 2007-12-15 20:59:51Z pronovic $
31 # Purpose : Implements the standard 'stage' action.
32 #
33 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
34
35 ########################################################################
36 # Module documentation
37 ########################################################################
38
39 """
40 Implements the standard 'stage' action.
41 @sort: executeStage
42 @author: Kenneth J. Pronovici <pronovic@ieee.org>
43 """
44
45
46 ########################################################################
47 # Imported modules
48 ########################################################################
49
50 # System modules
51 import os
52 import time
53 import logging
54
55 # Cedar Backup modules
56 from CedarBackup2.peer import RemotePeer, LocalPeer
57 from CedarBackup2.util import getUidGid, changeOwnership
58 from CedarBackup2.actions.constants import DIR_TIME_FORMAT, STAGE_INDICATOR
59 from CedarBackup2.actions.util import writeIndicatorFile
60
61
62 ########################################################################
63 # Module-wide constants and variables
64 ########################################################################
65
66 logger = logging.getLogger("CedarBackup2.log.actions.stage")
67
68
69 ########################################################################
70 # Public functions
71 ########################################################################
72
73 ##########################
74 # executeStage() function
75 ##########################
76
78 """
79 Executes the stage backup action.
80
81 @note: The daily directory is derived once and then we stick with it, just
82 in case a backup happens to span midnite.
83
84 @note: As portions of the stage action is complete, we will write various
85 indicator files so that it's obvious what actions have been completed. Each
86 peer gets a stage indicator in its collect directory, and then the master
87 gets a stage indicator in its daily staging directory. The store process
88 uses the master's stage indicator to decide whether a directory is ready to
89 be stored. Currently, nothing uses the indicator at each peer, and it
90 exists for reference only.
91
92 @param configPath: Path to configuration file on disk.
93 @type configPath: String representing a path on disk.
94
95 @param options: Program command-line options.
96 @type options: Options object.
97
98 @param config: Program configuration.
99 @type config: Config object.
100
101 @raise ValueError: Under many generic error conditions
102 @raise IOError: If there are problems reading or writing files.
103 """
104 logger.debug("Executing the 'stage' action.")
105 if config.options is None or config.stage is None:
106 raise ValueError("Stage configuration is not properly filled in.")
107 dailyDir = _getDailyDir(config)
108 localPeers = _getLocalPeers(config)
109 remotePeers = _getRemotePeers(config)
110 allPeers = localPeers + remotePeers
111 stagingDirs = _createStagingDirs(config, dailyDir, allPeers)
112 for peer in allPeers:
113 logger.info("Staging peer [%s]." % peer.name)
114 if not peer.checkCollectIndicator():
115 logger.error("Peer [%s] was not ready to be staged." % peer.name)
116 continue
117 logger.debug("Found collect indicator.")
118 targetDir = stagingDirs[peer.name]
119 ownership = getUidGid(config.options.backupUser, config.options.backupGroup)
120 logger.debug("Using target dir [%s], ownership [%d:%d]." % (targetDir, ownership[0], ownership[1]))
121 try:
122 count = peer.stagePeer(targetDir=targetDir, ownership=ownership) # note: utilize effective user's default umask
123 logger.info("Staged %d files for peer [%s]." % (count, peer.name))
124 peer.writeStageIndicator()
125 except (ValueError, IOError, OSError), e:
126 logger.error("Error staging [%s]: %s" % (peer.name, e))
127 writeIndicatorFile(dailyDir, STAGE_INDICATOR, config.options.backupUser, config.options.backupGroup)
128 logger.info("Executed the 'stage' action successfully.")
129
130
131 ########################################################################
132 # Private utility functions
133 ########################################################################
134
135 ################################
136 # _createStagingDirs() function
137 ################################
138
140 """
141 Creates staging directories as required.
142
143 The main staging directory is the passed in daily directory, something like
144 C{staging/2002/05/23}. Then, individual peers get their own directories,
145 i.e. C{staging/2002/05/23/host}.
146
147 @param config: Config object.
148 @param dailyDir: Daily staging directory.
149 @param peers: List of all configured peers.
150
151 @return: Dictionary mapping peer name to staging directory.
152 """
153 mapping = {}
154 if os.path.isdir(dailyDir):
155 logger.warn("Staging directory [%s] already existed." % dailyDir)
156 else:
157 try:
158 logger.debug("Creating staging directory [%s]." % dailyDir)
159 os.makedirs(dailyDir)
160 for path in [ dailyDir, os.path.join(dailyDir, ".."), os.path.join(dailyDir, "..", ".."), ]:
161 changeOwnership(path, config.options.backupUser, config.options.backupGroup)
162 except Exception, e:
163 raise Exception("Unable to create staging directory: %s" % e)
164 for peer in peers:
165 peerDir = os.path.join(dailyDir, peer.name)
166 mapping[peer.name] = peerDir
167 if os.path.isdir(peerDir):
168 logger.warn("Peer staging directory [%s] already existed." % peerDir)
169 else:
170 try:
171 logger.debug("Creating peer staging directory [%s]." % peerDir)
172 os.makedirs(peerDir)
173 changeOwnership(peerDir, config.options.backupUser, config.options.backupGroup)
174 except Exception, e:
175 raise Exception("Unable to create staging directory: %s" % e)
176 return mapping
177
178
179 ########################################################################
180 # Private attribute "getter" functions
181 ########################################################################
182
183 ##########################
184 # _getDailyDir() function
185 ##########################
186
188 """
189 Gets the daily staging directory.
190
191 This is just a directory in the form C{staging/YYYY/MM/DD}, i.e.
192 C{staging/2000/10/07}, except it will be an absolute path based on
193 C{config.stage.targetDir}.
194
195 @param config: Config object
196
197 @return: Path of daily staging directory.
198 """
199 dailyDir = os.path.join(config.stage.targetDir, time.strftime(DIR_TIME_FORMAT))
200 logger.debug("Daily staging directory is [%s]." % dailyDir)
201 return dailyDir
202
203
204 ############################
205 # _getLocalPeers() function
206 ############################
207
209 """
210 Return a list of L{LocalPeer} objects based on configuration.
211 @param config: Config object.
212 @return: List of L{LocalPeer} objects.
213 """
214 localPeers = []
215 configPeers = None
216 if config.stage.hasPeers():
217 logger.debug("Using list of local peers from stage configuration.")
218 configPeers = config.stage.localPeers
219 elif config.peers is not None and config.peers.hasPeers():
220 logger.debug("Using list of local peers from peers configuration.")
221 configPeers = config.peers.localPeers
222 if configPeers is not None:
223 for peer in configPeers:
224 localPeer = LocalPeer(peer.name, peer.collectDir)
225 localPeers.append(localPeer)
226 logger.debug("Found local peer: [%s]" % localPeer.name)
227 return localPeers
228
229
230 #############################
231 # _getRemotePeers() function
232 #############################
233
235 """
236 Return a list of L{RemotePeer} objects based on configuration.
237 @param config: Config object.
238 @return: List of L{RemotePeer} objects.
239 """
240 remotePeers = []
241 configPeers = None
242 if config.stage.hasPeers():
243 logger.debug("Using list of remote peers from stage configuration.")
244 configPeers = config.stage.remotePeers
245 elif config.peers is not None and config.peers.hasPeers():
246 logger.debug("Using list of remote peers from peers configuration.")
247 configPeers = config.peers.remotePeers
248 if configPeers is not None:
249 for peer in configPeers:
250 remoteUser = _getRemoteUser(config, peer)
251 rcpCommand = _getRcpCommand(config, peer)
252 remotePeer = RemotePeer(peer.name, peer.collectDir, config.options.workingDir,
253 remoteUser, rcpCommand, config.options.backupUser)
254 remotePeers.append(remotePeer)
255 logger.debug("Found remote peer: [%s]" % remotePeer.name)
256 return remotePeers
257
258
259 ############################
260 # _getRemoteUser() function
261 ############################
262
264 """
265 Gets the remote user associated with a remote peer.
266 Use peer's if possible, otherwise take from options section.
267 @param config: Config object.
268 @param remotePeer: Configuration-style remote peer object.
269 @return: Name of remote user associated with remote peer.
270 """
271 if remotePeer.remoteUser is None:
272 return config.options.backupUser
273 return remotePeer.remoteUser
274
275
276 ############################
277 # _getRcpCommand() function
278 ############################
279
281 """
282 Gets the RCP command associated with a remote peer.
283 Use peer's if possible, otherwise take from options section.
284 @param config: Config object.
285 @param remotePeer: Configuration-style remote peer object.
286 @return: RCP command associated with remote peer.
287 """
288 if remotePeer.rcpCommand is None:
289 return config.options.rcpCommand
290 return remotePeer.rcpCommand
291
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Thu Feb 7 09:26:51 2008 | http://epydoc.sourceforge.net |