| 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 |