CedarBackup2.extend.sysinfo

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 (>= 2.7)
     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