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