Package CedarBackup2 :: Package extend :: Module sysinfo
[hide private]
[frames] | no frames]

Source Code for Module CedarBackup2.extend.sysinfo

  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) 2005,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  : Official Cedar Backup Extensions 
 30  # Purpose  : Provides an extension to save off important system recovery information. 
 31  # 
 32  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
 33   
 34  ######################################################################## 
 35  # Module documentation 
 36  ######################################################################## 
 37   
 38  """ 
 39  Provides an extension to save off important system recovery information. 
 40   
 41  This is a simple Cedar Backup extension used to save off important system 
 42  recovery information.  It saves off three types of information: 
 43   
 44     - Currently-installed Debian packages via C{dpkg --get-selections} 
 45     - Disk partition information via C{fdisk -l} 
 46     - System-wide mounted filesystem contents, via C{ls -laR} 
 47   
 48  The saved-off information is placed into the collect directory and is 
 49  compressed using C{bzip2} to save space. 
 50   
 51  This extension relies on the options and collect configurations in the standard 
 52  Cedar Backup configuration file, but requires no new configuration of its own. 
 53  No public functions other than the action are exposed since all of this is 
 54  pretty simple. 
 55   
 56  @note: If the C{dpkg} or C{fdisk} commands cannot be found in their normal 
 57  locations or executed by the current user, those steps will be skipped and a 
 58  note will be logged at the INFO level. 
 59   
 60  @author: Kenneth J. Pronovici <pronovic@ieee.org> 
 61  """ 
 62   
 63  ######################################################################## 
 64  # Imported modules 
 65  ######################################################################## 
 66   
 67  # System modules 
 68  import os 
 69  import logging 
 70  from bz2 import BZ2File 
 71   
 72  # Cedar Backup modules 
 73  from CedarBackup2.util import resolveCommand, executeCommand, changeOwnership 
 74   
 75   
 76  ######################################################################## 
 77  # Module-wide constants and variables 
 78  ######################################################################## 
 79   
 80  logger = logging.getLogger("CedarBackup2.log.extend.sysinfo") 
 81   
 82  DPKG_PATH      = "/usr/bin/dpkg" 
 83  FDISK_PATH     = "/sbin/fdisk" 
 84   
 85  DPKG_COMMAND   = [ DPKG_PATH, "--get-selections", ] 
 86  FDISK_COMMAND  = [ FDISK_PATH, "-l", ] 
 87  LS_COMMAND     = [ "ls", "-laR", "/", ] 
 88   
 89   
 90  ######################################################################## 
 91  # Public functions 
 92  ######################################################################## 
 93   
 94  ########################### 
 95  # executeAction() function 
 96  ########################### 
 97   
98 -def executeAction(configPath, options, config):
99 """ 100 Executes the sysinfo backup action. 101 102 @param configPath: Path to configuration file on disk. 103 @type configPath: String representing a path on disk. 104 105 @param options: Program command-line options. 106 @type options: Options object. 107 108 @param config: Program configuration. 109 @type config: Config object. 110 111 @raise ValueError: Under many generic error conditions 112 @raise IOError: If the backup process fails for some reason. 113 """ 114 logger.debug("Executing sysinfo extended action.") 115 if config.options is None or config.collect is None: 116 raise ValueError("Cedar Backup configuration is not properly filled in.") 117 _dumpDebianPackages(config.collect.targetDir, config.options.backupUser, config.options.backupGroup) 118 _dumpPartitionTable(config.collect.targetDir, config.options.backupUser, config.options.backupGroup) 119 _dumpFilesystemContents(config.collect.targetDir, config.options.backupUser, config.options.backupGroup) 120 logger.info("Executed the sysinfo extended action successfully.")
121
122 -def _dumpDebianPackages(targetDir, backupUser, backupGroup, compress=True):
123 """ 124 Dumps a list of currently installed Debian packages via C{dpkg}. 125 @param targetDir: Directory to write output file into. 126 @param backupUser: User which should own the resulting file. 127 @param backupGroup: Group which should own the resulting file. 128 @param compress: Indicates whether to compress the output file. 129 @raise IOError: If the dump fails for some reason. 130 """ 131 if not os.path.exists(DPKG_PATH): 132 logger.info("Not executing Debian package dump since %s doesn't seem to exist." % DPKG_PATH) 133 elif not os.access(DPKG_PATH, os.X_OK): 134 logger.info("Not executing Debian package dump since %s cannot be executed." % DPKG_PATH) 135 else: 136 (outputFile, filename) = _getOutputFile(targetDir, "dpkg-selections", compress) 137 try: 138 command = resolveCommand(DPKG_COMMAND) 139 result = executeCommand(command, [], returnOutput=False, ignoreStderr=True, doNotLog=True, outputFile=outputFile)[0] 140 if result != 0: 141 raise IOError("Error [%d] executing Debian package dump." % result) 142 finally: 143 outputFile.close() 144 if not os.path.exists(filename): 145 raise IOError("File [%s] does not seem to exist after Debian package dump finished." % filename) 146 changeOwnership(filename, backupUser, backupGroup)
147
148 -def _dumpPartitionTable(targetDir, backupUser, backupGroup, compress=True):
149 """ 150 Dumps information about the partition table via C{fdisk}. 151 @param targetDir: Directory to write output file into. 152 @param backupUser: User which should own the resulting file. 153 @param backupGroup: Group which should own the resulting file. 154 @param compress: Indicates whether to compress the output file. 155 @raise IOError: If the dump fails for some reason. 156 """ 157 if not os.path.exists(FDISK_PATH): 158 logger.info("Not executing partition table dump since %s doesn't seem to exist." % FDISK_PATH) 159 elif not os.access(FDISK_PATH, os.X_OK): 160 logger.info("Not executing partition table dump since %s cannot be executed." % FDISK_PATH) 161 else: 162 (outputFile, filename) = _getOutputFile(targetDir, "fdisk-l", compress) 163 try: 164 command = resolveCommand(FDISK_COMMAND) 165 result = executeCommand(command, [], returnOutput=False, ignoreStderr=True, outputFile=outputFile)[0] 166 if result != 0: 167 raise IOError("Error [%d] executing partition table dump." % result) 168 finally: 169 outputFile.close() 170 if not os.path.exists(filename): 171 raise IOError("File [%s] does not seem to exist after partition table dump finished." % filename) 172 changeOwnership(filename, backupUser, backupGroup)
173
174 -def _dumpFilesystemContents(targetDir, backupUser, backupGroup, compress=True):
175 """ 176 Dumps complete listing of filesystem contents via C{ls -laR}. 177 @param targetDir: Directory to write output file into. 178 @param backupUser: User which should own the resulting file. 179 @param backupGroup: Group which should own the resulting file. 180 @param compress: Indicates whether to compress the output file. 181 @raise IOError: If the dump fails for some reason. 182 """ 183 (outputFile, filename) = _getOutputFile(targetDir, "ls-laR", compress) 184 try: 185 # Note: can't count on return status from 'ls', so we don't check it. 186 command = resolveCommand(LS_COMMAND) 187 executeCommand(command, [], returnOutput=False, ignoreStderr=True, doNotLog=True, outputFile=outputFile) 188 finally: 189 outputFile.close() 190 if not os.path.exists(filename): 191 raise IOError("File [%s] does not seem to exist after filesystem contents dump finished." % filename) 192 changeOwnership(filename, backupUser, backupGroup)
193
194 -def _getOutputFile(targetDir, name, compress=True):
195 """ 196 Opens the output file used for saving a dump to the filesystem. 197 198 The filename will be C{name.txt} (or C{name.txt.bz2} if C{compress} is 199 C{True}), written in the target directory. 200 201 @param targetDir: Target directory to write file in. 202 @param name: Name of the file to create. 203 @param compress: Indicates whether to write compressed output. 204 205 @return: Tuple of (Output file object, filename) 206 """ 207 filename = os.path.join(targetDir, "%s.txt" % name) 208 if compress: 209 filename = "%s.bz2" % filename 210 logger.debug("Dump file will be [%s]." % filename) 211 if compress: 212 outputFile = BZ2File(filename, "w") 213 else: 214 outputFile = open(filename, "w") 215 return (outputFile, filename)
216