Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# Authors: # Petr Viktorin <pviktori@redhat.com> # # Copyright (C) 2012 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>.
Handles common operations like option parsing and logging """
"""An exception that records an error message and a return value """ self.msg = msg self.rval = rval
return self.msg or ''
"""Base class for command-line admin tools
To run the tool, call the main() classmethod with a list of command-line arguments. Alternatively, call run_as_script() to run with command-line arguments in sys.argv, and call sys.exit() with the return value.
Some commands actually represent multiple related tools, e.g. ``ipa-server-install`` and ``ipa-server-install --uninstall`` would be represented by separate classes. Only their options are the same.
To handle this, AdminTool provides classmethods for option parsing and selecting the appropriate command class.
A class-wide option parser is made by calling add_options. The options are then parsed into options and arguments, and get_command_class is called with those to retrieve the class. That class is then instantiated and run.
Running consists of a few steps: - validating options or the environment (validate_options) - setting up logging (setup_logging) - running the actual command (run)
Any unhandled exceptions are handled in handle_error. And at the end, either log_success or log_failure is called.
Class attributes to define in subclasses: command_name - shown in logs log_file_name - if None, logging is to stderr only needs_root - if true, non-root users can't run the tool usage - text shown in help """
def make_parser(cls): """Create an option parser shared across all instances of this class""" parser = config.IPAOptionParser(version=version.VERSION, usage=cls.usage, formatter=config.IPAFormatter()) cls.option_parser = parser cls.add_options(parser)
def add_options(cls, parser): """Add command-specific options to the option parser""" parser.add_option("-d", "--debug", dest="debug", default=False, action="store_true", help="print debugging information")
def run_as_script(cls): """Run this command with sys.argv, exit process with the return value """ sys.exit(cls.main(sys.argv))
def main(cls, argv): """The main entry point
Parses command-line arguments, selects the actual command class to use based on them, and runs that command.
:param argv: Command-line arguments. If None, ``sys.argv`` is used. """ if argv is None: argv = sys.argv if cls not in cls._option_parsers: # We use cls._option_parsers, a dictionary keyed on class, to check # if we need to create a parser. This is because cls.option_parser # can refer to the parser of a superclass. cls.make_parser() cls._option_parsers[cls] = cls.option_parser
options, args = cls.option_parser.parse_args(argv[1:])
command_class = cls.get_command_class(options, args) command = command_class(options, args)
return command.execute()
def get_command_class(cls, options, args): return cls
self.options = options self.args = args self.safe_options = self.option_parser.get_safe_opts(options)
"""Do everything needed after options are parsed
This includes validating options, setting up logging, doing the actual work, and handling the result. """ try: self.validate_options() self.setup_logging() self.run() except BaseException, exception: traceback = sys.exc_info()[2] error_message, return_value = self.handle_error(exception) else: return_value = 0 if return_value: self.log_failure(error_message, return_value, exception, traceback) return return_value else: self.log_success() return 0
"""Validate self.options
It's also possible to compute and store information that will be useful later, but no changes to the system should be made here. """ self.run_by_root = os.getegid() == 0 if self.needs_root and not self.run_by_root: raise ScriptError('Must be root to run %s' % self.command_name, 1)
ipa_log_manager.standard_logging_setup( self.log_file_name, debug=self.options.debug) self.logger = ipa_log_manager.root_logger
"""Given an exception, return a message (or None) and process exit code """ if isinstance(exception, ScriptError): return exception.msg, exception.rval or 1 elif isinstance(exception, SystemExit): if isinstance(exception.code, int): return None, exception.code return str(exception.code), 1
return str(exception), 1
"""Actual running of the command
This is where the hard work is done. The base implementation logs the invocation of the command. """ self.logger.debug( '%s was invoked with arguments %s and options: %s' % ( self.command_name, self.args, self.safe_options))
self.logger.error(error_message) self.logger.info('\n'.join(traceback.format_tb(backtrace))) self.logger.info('The %s command failed, exception: %s: %s', self.command_name, type(exception).__name__, exception) print >> sys.stderr, error_message
self.logger.info('The %s command was successful', self.command_name) |