| 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) 2007,2010 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.5)
29 # Project : Cedar Backup, release 2
30 # Revision : $Id: util.py 1041 2013-05-10 02:05:13Z pronovic $
31 # Purpose : Implements action-related utilities
32 #
33 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
34
35 ########################################################################
36 # Module documentation
37 ########################################################################
38
39 """
40 Implements action-related utilities
41 @sort: findDailyDirs
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 tempfile
54 import logging
55
56 # Cedar Backup modules
57 from CedarBackup2.filesystem import FilesystemList
58 from CedarBackup2.util import changeOwnership
59 from CedarBackup2.util import deviceMounted
60 from CedarBackup2.writers.util import readMediaLabel
61 from CedarBackup2.writers.cdwriter import CdWriter
62 from CedarBackup2.writers.dvdwriter import DvdWriter
63 from CedarBackup2.writers.cdwriter import MEDIA_CDR_74, MEDIA_CDR_80, MEDIA_CDRW_74, MEDIA_CDRW_80
64 from CedarBackup2.writers.dvdwriter import MEDIA_DVDPLUSR, MEDIA_DVDPLUSRW
65 from CedarBackup2.config import DEFAULT_MEDIA_TYPE, DEFAULT_DEVICE_TYPE, REWRITABLE_MEDIA_TYPES
66 from CedarBackup2.actions.constants import INDICATOR_PATTERN
67
68
69 ########################################################################
70 # Module-wide constants and variables
71 ########################################################################
72
73 logger = logging.getLogger("CedarBackup2.log.actions.util")
74 MEDIA_LABEL_PREFIX = "CEDAR BACKUP"
75
76
77 ########################################################################
78 # Public utility functions
79 ########################################################################
80
81 ###########################
82 # findDailyDirs() function
83 ###########################
84
86 """
87 Returns a list of all daily staging directories that do not contain
88 the indicated indicator file.
89
90 @param stagingDir: Configured staging directory (config.targetDir)
91
92 @return: List of absolute paths to daily staging directories.
93 """
94 results = FilesystemList()
95 yearDirs = FilesystemList()
96 yearDirs.excludeFiles = True
97 yearDirs.excludeLinks = True
98 yearDirs.addDirContents(path=stagingDir, recursive=False, addSelf=False)
99 for yearDir in yearDirs:
100 monthDirs = FilesystemList()
101 monthDirs.excludeFiles = True
102 monthDirs.excludeLinks = True
103 monthDirs.addDirContents(path=yearDir, recursive=False, addSelf=False)
104 for monthDir in monthDirs:
105 dailyDirs = FilesystemList()
106 dailyDirs.excludeFiles = True
107 dailyDirs.excludeLinks = True
108 dailyDirs.addDirContents(path=monthDir, recursive=False, addSelf=False)
109 for dailyDir in dailyDirs:
110 if os.path.exists(os.path.join(dailyDir, indicatorFile)):
111 logger.debug("Skipping directory [%s]; contains %s." % (dailyDir, indicatorFile))
112 else:
113 logger.debug("Adding [%s] to list of daily directories." % dailyDir)
114 results.append(dailyDir) # just put it in the list, no fancy operations
115 return results
116
117
118 ###########################
119 # createWriter() function
120 ###########################
121
123 """
124 Creates a writer object based on current configuration.
125
126 This function creates and returns a writer based on configuration. This is
127 done to abstract action functionality from knowing what kind of writer is in
128 use. Since all writers implement the same interface, there's no need for
129 actions to care which one they're working with.
130
131 Currently, the C{cdwriter} and C{dvdwriter} device types are allowed. An
132 exception will be raised if any other device type is used.
133
134 This function also checks to make sure that the device isn't mounted before
135 creating a writer object for it. Experience shows that sometimes if the
136 device is mounted, we have problems with the backup. We may as well do the
137 check here first, before instantiating the writer.
138
139 @param config: Config object.
140
141 @return: Writer that can be used to write a directory to some media.
142
143 @raise ValueError: If there is a problem getting the writer.
144 @raise IOError: If there is a problem creating the writer object.
145 """
146 devicePath = config.store.devicePath
147 deviceScsiId = config.store.deviceScsiId
148 driveSpeed = config.store.driveSpeed
149 noEject = config.store.noEject
150 refreshMediaDelay = config.store.refreshMediaDelay
151 ejectDelay = config.store.ejectDelay
152 deviceType = _getDeviceType(config)
153 mediaType = _getMediaType(config)
154 if deviceMounted(devicePath):
155 raise IOError("Device [%s] is currently mounted." % (devicePath))
156 if deviceType == "cdwriter":
157 return CdWriter(devicePath, deviceScsiId, driveSpeed, mediaType, noEject, refreshMediaDelay, ejectDelay)
158 elif deviceType == "dvdwriter":
159 return DvdWriter(devicePath, deviceScsiId, driveSpeed, mediaType, noEject, refreshMediaDelay, ejectDelay)
160 else:
161 raise ValueError("Device type [%s] is invalid." % deviceType)
162
163
164 ################################
165 # writeIndicatorFile() function
166 ################################
167
169 """
170 Writes an indicator file into a target directory.
171 @param targetDir: Target directory in which to write indicator
172 @param indicatorFile: Name of the indicator file
173 @param backupUser: User that indicator file should be owned by
174 @param backupGroup: Group that indicator file should be owned by
175 @raise IOException: If there is a problem writing the indicator file
176 """
177 filename = os.path.join(targetDir, indicatorFile)
178 logger.debug("Writing indicator file [%s]." % filename)
179 try:
180 open(filename, "w").write("")
181 changeOwnership(filename, backupUser, backupGroup)
182 except Exception, e:
183 logger.error("Error writing [%s]: %s" % (filename, e))
184 raise e
185
186
187 ############################
188 # getBackupFiles() function
189 ############################
190
192 """
193 Gets a list of backup files in a target directory.
194
195 Files that match INDICATOR_PATTERN (i.e. C{"cback.store"}, C{"cback.stage"},
196 etc.) are assumed to be indicator files and are ignored.
197
198 @param targetDir: Directory to look in
199
200 @return: List of backup files in the directory
201
202 @raise ValueError: If the target directory does not exist
203 """
204 if not os.path.isdir(targetDir):
205 raise ValueError("Target directory [%s] is not a directory or does not exist." % targetDir)
206 fileList = FilesystemList()
207 fileList.excludeDirs = True
208 fileList.excludeLinks = True
209 fileList.excludeBasenamePatterns = INDICATOR_PATTERN
210 fileList.addDirContents(targetDir)
211 return fileList
212
213
214 ####################
215 # checkMediaState()
216 ####################
217
219 """
220 Checks state of the media in the backup device to confirm whether it has
221 been initialized for use with Cedar Backup.
222
223 We can tell whether the media has been initialized by looking at its media
224 label. If the media label starts with MEDIA_LABEL_PREFIX, then it has been
225 initialized.
226
227 The check varies depending on whether the media is rewritable or not. For
228 non-rewritable media, we also accept a C{None} media label, since this kind
229 of media cannot safely be initialized.
230
231 @param storeConfig: Store configuration
232
233 @raise ValueError: If media is not initialized.
234 """
235 mediaLabel = readMediaLabel(storeConfig.devicePath)
236 if storeConfig.mediaType in REWRITABLE_MEDIA_TYPES:
237 if mediaLabel is None:
238 raise ValueError("Media has not been initialized: no media label available")
239 elif not mediaLabel.startswith(MEDIA_LABEL_PREFIX):
240 raise ValueError("Media has not been initialized: unrecognized media label [%s]" % mediaLabel)
241 else:
242 if mediaLabel is None:
243 logger.info("Media has no media label; assuming OK since media is not rewritable.")
244 elif not mediaLabel.startswith(MEDIA_LABEL_PREFIX):
245 raise ValueError("Media has not been initialized: unrecognized media label [%s]" % mediaLabel)
246
247
248 #########################
249 # initializeMediaState()
250 #########################
251
253 """
254 Initializes state of the media in the backup device so Cedar Backup can
255 recognize it.
256
257 This is done by writing an mostly-empty image (it contains a "Cedar Backup"
258 directory) to the media with a known media label.
259
260 @note: Only rewritable media (CD-RW, DVD+RW) can be initialized. It
261 doesn't make any sense to initialize media that cannot be rewritten (CD-R,
262 DVD+R), since Cedar Backup would then not be able to use that media for a
263 backup.
264
265 @param config: Cedar Backup configuration
266
267 @raise ValueError: If media could not be initialized.
268 @raise ValueError: If the configured media type is not rewritable
269 """
270 if not config.store.mediaType in REWRITABLE_MEDIA_TYPES:
271 raise ValueError("Only rewritable media types can be initialized.")
272 mediaLabel = buildMediaLabel()
273 writer = createWriter(config)
274 writer.refreshMedia()
275 writer.initializeImage(True, config.options.workingDir, mediaLabel) # always create a new disc
276 tempdir = tempfile.mkdtemp(dir=config.options.workingDir)
277 try:
278 writer.addImageEntry(tempdir, "CedarBackup")
279 writer.writeImage()
280 finally:
281 if os.path.exists(tempdir):
282 try:
283 os.rmdir(tempdir)
284 except: pass
285
286
287 ####################
288 # buildMediaLabel()
289 ####################
290
292 """
293 Builds a media label to be used on Cedar Backup media.
294 @return: Media label as a string.
295 """
296 currentDate = time.strftime("%d-%b-%Y").upper()
297 return "%s %s" % (MEDIA_LABEL_PREFIX, currentDate)
298
299
300 ########################################################################
301 # Private attribute "getter" functions
302 ########################################################################
303
304 ############################
305 # _getDeviceType() function
306 ############################
307
309 """
310 Gets the device type that should be used for storing.
311
312 Use the configured device type if not C{None}, otherwise use
313 L{config.DEFAULT_DEVICE_TYPE}.
314
315 @param config: Config object.
316 @return: Device type to be used.
317 """
318 if config.store.deviceType is None:
319 deviceType = DEFAULT_DEVICE_TYPE
320 else:
321 deviceType = config.store.deviceType
322 logger.debug("Device type is [%s]" % deviceType)
323 return deviceType
324
325
326 ###########################
327 # _getMediaType() function
328 ###########################
329
331 """
332 Gets the media type that should be used for storing.
333
334 Use the configured media type if not C{None}, otherwise use
335 C{DEFAULT_MEDIA_TYPE}.
336
337 Once we figure out what configuration value to use, we return a media type
338 value that is valid in one of the supported writers::
339
340 MEDIA_CDR_74
341 MEDIA_CDRW_74
342 MEDIA_CDR_80
343 MEDIA_CDRW_80
344 MEDIA_DVDPLUSR
345 MEDIA_DVDPLUSRW
346
347 @param config: Config object.
348
349 @return: Media type to be used as a writer media type value.
350 @raise ValueError: If the media type is not valid.
351 """
352 if config.store.mediaType is None:
353 mediaType = DEFAULT_MEDIA_TYPE
354 else:
355 mediaType = config.store.mediaType
356 if mediaType == "cdr-74":
357 logger.debug("Media type is MEDIA_CDR_74.")
358 return MEDIA_CDR_74
359 elif mediaType == "cdrw-74":
360 logger.debug("Media type is MEDIA_CDRW_74.")
361 return MEDIA_CDRW_74
362 elif mediaType == "cdr-80":
363 logger.debug("Media type is MEDIA_CDR_80.")
364 return MEDIA_CDR_80
365 elif mediaType == "cdrw-80":
366 logger.debug("Media type is MEDIA_CDRW_80.")
367 return MEDIA_CDRW_80
368 elif mediaType == "dvd+r":
369 logger.debug("Media type is MEDIA_DVDPLUSR.")
370 return MEDIA_DVDPLUSR
371 elif mediaType == "dvd+rw":
372 logger.debug("Media type is MEDIA_DVDPLUSRW.")
373 return MEDIA_DVDPLUSRW
374 else:
375 raise ValueError("Media type [%s] is not valid." % mediaType)
376
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Oct 7 20:31:35 2014 | http://epydoc.sourceforge.net |