| 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-2008 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 852 2008-03-16 23:34:19Z 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 if os.getuid() == 0:
120 # Since we're running as root, we can change ownership
121 ownership = getUidGid(config.options.backupUser, config.options.backupGroup)
122 logger.debug("Using target dir [%s], ownership [%d:%d]." % (targetDir, ownership[0], ownership[1]))
123 else:
124 # Non-root cannot change ownership, so don't set it
125 ownership = None
126 logger.debug("Using target dir [%s], ownership [None]." % targetDir)
127 try:
128 count = peer.stagePeer(targetDir=targetDir, ownership=ownership) # note: utilize effective user's default umask
129 logger.info("Staged %d files for peer [%s]." % (count, peer.name))
130 peer.writeStageIndicator()
131 except (ValueError, IOError, OSError), e:
132 logger.error("Error staging [%s]: %s" % (peer.name, e))
133 writeIndicatorFile(dailyDir, STAGE_INDICATOR, config.options.backupUser, config.options.backupGroup)
134 logger.info("Executed the 'stage' action successfully.")
135
136
137 ########################################################################
138 # Private utility functions
139 ########################################################################
140
141 ################################
142 # _createStagingDirs() function
143 ################################
144
146 """
147 Creates staging directories as required.
148
149 The main staging directory is the passed in daily directory, something like
150 C{staging/2002/05/23}. Then, individual peers get their own directories,
151 i.e. C{staging/2002/05/23/host}.
152
153 @param config: Config object.
154 @param dailyDir: Daily staging directory.
155 @param peers: List of all configured peers.
156
157 @return: Dictionary mapping peer name to staging directory.
158 """
159 mapping = {}
160 if os.path.isdir(dailyDir):
161 logger.warn("Staging directory [%s] already existed." % dailyDir)
162 else:
163 try:
164 logger.debug("Creating staging directory [%s]." % dailyDir)
165 os.makedirs(dailyDir)
166 for path in [ dailyDir, os.path.join(dailyDir, ".."), os.path.join(dailyDir, "..", ".."), ]:
167 changeOwnership(path, config.options.backupUser, config.options.backupGroup)
168 except Exception, e:
169 raise Exception("Unable to create staging directory: %s" % e)
170 for peer in peers:
171 peerDir = os.path.join(dailyDir, peer.name)
172 mapping[peer.name] = peerDir
173 if os.path.isdir(peerDir):
174 logger.warn("Peer staging directory [%s] already existed." % peerDir)
175 else:
176 try:
177 logger.debug("Creating peer staging directory [%s]." % peerDir)
178 os.makedirs(peerDir)
179 changeOwnership(peerDir, config.options.backupUser, config.options.backupGroup)
180 except Exception, e:
181 raise Exception("Unable to create staging directory: %s" % e)
182 return mapping
183
184
185 ########################################################################
186 # Private attribute "getter" functions
187 ########################################################################
188
189 ##########################
190 # _getDailyDir() function
191 ##########################
192
194 """
195 Gets the daily staging directory.
196
197 This is just a directory in the form C{staging/YYYY/MM/DD}, i.e.
198 C{staging/2000/10/07}, except it will be an absolute path based on
199 C{config.stage.targetDir}.
200
201 @param config: Config object
202
203 @return: Path of daily staging directory.
204 """
205 dailyDir = os.path.join(config.stage.targetDir, time.strftime(DIR_TIME_FORMAT))
206 logger.debug("Daily staging directory is [%s]." % dailyDir)
207 return dailyDir
208
209
210 ############################
211 # _getLocalPeers() function
212 ############################
213
215 """
216 Return a list of L{LocalPeer} objects based on configuration.
217 @param config: Config object.
218 @return: List of L{LocalPeer} objects.
219 """
220 localPeers = []
221 configPeers = None
222 if config.stage.hasPeers():
223 logger.debug("Using list of local peers from stage configuration.")
224 configPeers = config.stage.localPeers
225 elif config.peers is not None and config.peers.hasPeers():
226 logger.debug("Using list of local peers from peers configuration.")
227 configPeers = config.peers.localPeers
228 if configPeers is not None:
229 for peer in configPeers:
230 localPeer = LocalPeer(peer.name, peer.collectDir)
231 localPeers.append(localPeer)
232 logger.debug("Found local peer: [%s]" % localPeer.name)
233 return localPeers
234
235
236 #############################
237 # _getRemotePeers() function
238 #############################
239
241 """
242 Return a list of L{RemotePeer} objects based on configuration.
243 @param config: Config object.
244 @return: List of L{RemotePeer} objects.
245 """
246 remotePeers = []
247 configPeers = None
248 if config.stage.hasPeers():
249 logger.debug("Using list of remote peers from stage configuration.")
250 configPeers = config.stage.remotePeers
251 elif config.peers is not None and config.peers.hasPeers():
252 logger.debug("Using list of remote peers from peers configuration.")
253 configPeers = config.peers.remotePeers
254 if configPeers is not None:
255 for peer in configPeers:
256 remoteUser = _getRemoteUser(config, peer)
257 localUser = _getLocalUser(config)
258 rcpCommand = _getRcpCommand(config, peer)
259 remotePeer = RemotePeer(peer.name, peer.collectDir, config.options.workingDir,
260 remoteUser, rcpCommand, localUser)
261 remotePeers.append(remotePeer)
262 logger.debug("Found remote peer: [%s]" % remotePeer.name)
263 return remotePeers
264
265
266 ############################
267 # _getRemoteUser() function
268 ############################
269
271 """
272 Gets the remote user associated with a remote peer.
273 Use peer's if possible, otherwise take from options section.
274 @param config: Config object.
275 @param remotePeer: Configuration-style remote peer object.
276 @return: Name of remote user associated with remote peer.
277 """
278 if remotePeer.remoteUser is None:
279 return config.options.backupUser
280 return remotePeer.remoteUser
281
282
283 ###########################
284 # _getLocalUser() function
285 ###########################
286
288 """
289 Gets the remote user associated with a remote peer.
290 @param config: Config object.
291 @return: Name of local user that should be used
292 """
293 if os.getuid() != 0:
294 return None
295 return config.options.backupUser
296
297
298 ############################
299 # _getRcpCommand() function
300 ############################
301
303 """
304 Gets the RCP command associated with a remote peer.
305 Use peer's if possible, otherwise take from options section.
306 @param config: Config object.
307 @param remotePeer: Configuration-style remote peer object.
308 @return: RCP command associated with remote peer.
309 """
310 if remotePeer.rcpCommand is None:
311 return config.options.rcpCommand
312 return remotePeer.rcpCommand
313
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Mon May 5 19:58:37 2008 | http://epydoc.sourceforge.net |