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 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: util.py 747 2007-03-25 19:42:43Z 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 ########################### 8486 """ 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 results116 117 118 ########################### 119 # createWriter() function 120 ########################### 121123 """ 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 deviceType = _getDeviceType(config) 151 mediaType = _getMediaType(config) 152 if deviceMounted(devicePath): 153 raise IOError("Device [%s] is currently mounted." % (devicePath)) 154 if deviceType == "cdwriter": 155 return CdWriter(devicePath, deviceScsiId, driveSpeed, mediaType, noEject) 156 elif deviceType == "dvdwriter": 157 return DvdWriter(devicePath, deviceScsiId, driveSpeed, mediaType, noEject) 158 else: 159 raise ValueError("Device type [%s] is invalid." % deviceType)160 161 162 ################################ 163 # writeIndicatorFile() function 164 ################################ 165167 """ 168 Writes an indicator file into a target directory. 169 @param targetDir: Target directory in which to write indicator 170 @param indicatorFile: Name of the indicator file 171 @param backupUser: User that indicator file should be owned by 172 @param backupGroup: Group that indicator file should be owned by 173 @raise IOException: If there is a problem writing the indicator file 174 """ 175 filename = os.path.join(targetDir, indicatorFile) 176 logger.debug("Writing indicator file [%s]." % filename) 177 try: 178 open(filename, "w").write("") 179 changeOwnership(filename, backupUser, backupGroup) 180 except Exception, e: 181 logger.error("Error writing [%s]: %s" % (filename, e)) 182 raise e183 184 185 ############################ 186 # getBackupFiles() function 187 ############################ 188190 """ 191 Gets a list of backup files in a target directory. 192 193 Files that match INDICATOR_PATTERN (i.e. C{"cback.store"}, C{"cback.stage"}, 194 etc.) are assumed to be indicator files and are ignored. 195 196 @param targetDir: Directory to look in 197 198 @return: List of backup files in the directory 199 200 @raise ValueError: If the target directory does not exist 201 """ 202 if not os.path.isdir(targetDir): 203 raise ValueError("Target directory [%s] is not a directory or does not exist." % targetDir) 204 fileList = FilesystemList() 205 fileList.excludeDirs = True 206 fileList.excludeLinks = True 207 fileList.excludeBasenamePatterns = INDICATOR_PATTERN 208 fileList.addDirContents(targetDir) 209 return fileList210 211 212 #################### 213 # checkMediaState() 214 #################### 215217 """ 218 Checks state of the media in the backup device to confirm whether it has 219 been initialized for use with Cedar Backup. 220 221 We can tell whether the media has been initialized by looking at its media 222 label. If the media label starts with MEDIA_LABEL_PREFIX, then it has been 223 initialized. 224 225 The check varies depending on whether the media is rewritable or not. For 226 non-rewritable media, we also accept a C{None} media label, since this kind 227 of media cannot safely be initialized. 228 229 @param storeConfig: Store configuration 230 231 @raise ValueError: If media is not initialized. 232 """ 233 mediaLabel = readMediaLabel(storeConfig.devicePath) 234 if storeConfig.mediaType in REWRITABLE_MEDIA_TYPES: 235 if mediaLabel is None: 236 raise ValueError("Media has not been initialized: no media label available") 237 elif not mediaLabel.startswith(MEDIA_LABEL_PREFIX): 238 raise ValueError("Media has not been initialized: unrecognized media label [%s]" % mediaLabel) 239 else: 240 if mediaLabel is None: 241 logger.info("Media has no media label; assuming OK since media is not rewritable.") 242 elif not mediaLabel.startswith(MEDIA_LABEL_PREFIX): 243 raise ValueError("Media has not been initialized: unrecognized media label [%s]" % mediaLabel)244 245 246 ######################### 247 # initializeMediaState() 248 ######################### 249251 """ 252 Initializes state of the media in the backup device so Cedar Backup can 253 recognize it. 254 255 This is done by writing an mostly-empty image (it contains a "Cedar Backup" 256 directory) to the media with a known media label. 257 258 @note: Only rewritable media (CD-RW, DVD+RW) can be initialized. It 259 doesn't make any sense to initialize media that cannot be rewritten (CD-R, 260 DVD+R), since Cedar Backup would then not be able to use that media for a 261 backup. 262 263 @param config: Cedar Backup configuration 264 265 @raise ValueError: If media could not be initialized. 266 @raise ValueError: If the configured media type is not rewritable 267 """ 268 if not config.store.mediaType in REWRITABLE_MEDIA_TYPES: 269 raise ValueError("Only rewritable media types can be initialized.") 270 mediaLabel = buildMediaLabel() 271 writer = createWriter(config) 272 writer.initializeImage(True, config.options.workingDir, mediaLabel) # always create a new disc 273 tempdir = tempfile.mkdtemp(dir=config.options.workingDir) 274 try: 275 writer.addImageEntry(tempdir, "CedarBackup") 276 writer.writeImage() 277 finally: 278 if os.path.exists(tempdir): 279 try: 280 os.rmdir(tempdir) 281 except: pass282 283 284 #################### 285 # buildMediaLabel() 286 #################### 287289 """ 290 Builds a media label to be used on Cedar Backup media. 291 @return: Media label as a string. 292 """ 293 currentDate = time.strftime("%d-%b-%Y").upper() 294 return "%s %s" % (MEDIA_LABEL_PREFIX, currentDate)295 296 297 ######################################################################## 298 # Private attribute "getter" functions 299 ######################################################################## 300 301 ############################ 302 # _getDeviceType() function 303 ############################ 304306 """ 307 Gets the device type that should be used for storing. 308 309 Use the configured device type if not C{None}, otherwise use 310 L{config.DEFAULT_DEVICE_TYPE}. 311 312 @param config: Config object. 313 @return: Device type to be used. 314 """ 315 if config.store.deviceType is None: 316 deviceType = DEFAULT_DEVICE_TYPE 317 else: 318 deviceType = config.store.deviceType 319 logger.debug("Device type is [%s]" % deviceType) 320 return deviceType321 322 323 ########################### 324 # _getMediaType() function 325 ########################### 326328 """ 329 Gets the media type that should be used for storing. 330 331 Use the configured media type if not C{None}, otherwise use 332 C{DEFAULT_MEDIA_TYPE}. 333 334 Once we figure out what configuration value to use, we return a media type 335 value that is valid in one of the supported writers:: 336 337 MEDIA_CDR_74 338 MEDIA_CDRW_74 339 MEDIA_CDR_80 340 MEDIA_CDRW_80 341 MEDIA_DVDPLUSR 342 MEDIA_DVDPLUSRW 343 344 @param config: Config object. 345 346 @return: Media type to be used as a writer media type value. 347 @raise ValueError: If the media type is not valid. 348 """ 349 if config.store.mediaType is None: 350 mediaType = DEFAULT_MEDIA_TYPE 351 else: 352 mediaType = config.store.mediaType 353 if mediaType == "cdr-74": 354 logger.debug("Media type is MEDIA_CDR_74.") 355 return MEDIA_CDR_74 356 elif mediaType == "cdrw-74": 357 logger.debug("Media type is MEDIA_CDRW_74.") 358 return MEDIA_CDRW_74 359 elif mediaType == "cdr-80": 360 logger.debug("Media type is MEDIA_CDR_80.") 361 return MEDIA_CDR_80 362 elif mediaType == "cdrw-80": 363 logger.debug("Media type is MEDIA_CDRW_80.") 364 return MEDIA_CDRW_80 365 elif mediaType == "dvd+r": 366 logger.debug("Media type is MEDIA_DVDPLUSR.") 367 return MEDIA_DVDPLUSR 368 elif mediaType == "dvd+rw": 369 logger.debug("Media type is MEDIA_DVDPLUSRW.") 370 return MEDIA_DVDPLUSR 371 else: 372 raise ValueError("Media type [%s] is not valid." % mediaType)373
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0beta1 on Mon May 5 19:58:20 2008 | http://epydoc.sourceforge.net |