aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJake Hunsaker <jhunsake@redhat.com>2020-03-26 17:04:28 -0400
committerJake Hunsaker <jhunsake@redhat.com>2020-04-08 09:27:16 -0400
commit6a3b296de560e6b4abc1ec56cf34b0028a04a878 (patch)
tree3f91e9184bccbdc55c7075c4867e60c968f3d25f
parent5b7717775ca8b26a1fde76a163d604f40d724721 (diff)
downloadsos-6a3b296de560e6b4abc1ec56cf34b0028a04a878.tar.gz
[component] Add Policy loading and move to new component.py
Adds Policy loading into `SoSComponent()` so that any subcommand can, if it needs it, have policies loaded consistenly. This is controlled via the `load_policy` class attr, which defaults to True. Future subcommands that do not need to have a policy loaded (E.G. the planned `info` command), can simply set this to False in order to skip this step. Moves `SoSComponent()` out of sos/__init__.py and into sos/component.py to ease import conflicts arising from policy loading. Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r--sos/__init__.py145
-rw-r--r--sos/component.py171
2 files changed, 172 insertions, 144 deletions
diff --git a/sos/__init__.py b/sos/__init__.py
index 10f67b93..e367d6a7 100644
--- a/sos/__init__.py
+++ b/sos/__init__.py
@@ -22,150 +22,7 @@ import sys
import tempfile
from argparse import ArgumentParser
-from sos.options import SoSOptions, SosListOption
-from sos.utilities import TempFileUtil
-
-
-class SoSComponent():
- """Any sub-command that sos supports needs to subclass SoSComponent in
- order to be properly supported by the sos binary.
-
- This class contains the standardized entrypoint for subcommands, as well as
- building out supported options from both globally shared option lists, and
- options supported by that specific subcommand.
-
- When sos initializes, it will load an unintialized instance of each class
- found within one recursion of the module root directory that subclasses
- SoSComponent.
-
- If sos is able to match the user-specified subcommand to one that exists
- locally, then that SoSComponent is initialized, logging is setup, and a
- policy is loaded. From there, the component's execute() method takes over.
-
- Added in 4.0
- """
-
- desc = 'unset'
-
- arg_defaults = {}
- configure_logging = True
-
- _arg_defaults = {
- "config_file": '/etc/sos.conf',
- "quiet": False,
- "tmp_dir": '',
- "sysroot": None,
- "verbosity": 0
- }
-
- def __init__(self, parser, parsed_args, cmdline_args):
- self.parser = parser
- self.args = parsed_args
- self.cmdline = cmdline_args
- self.exit_process = False
-
- try:
- import signal
- signal.signal(signal.SIGTERM, self.get_exit_handler())
- except Exception:
- pass
-
- # update args from component's arg_defaults defintion
- self._arg_defaults.update(self.arg_defaults)
- self.opts = self.load_options()
- if self.configure_logging:
- tmpdir = self.opts.tmp_dir or tempfile.gettempdir()
- self.tmpdir = tempfile.mkdtemp(prefix="sos.", dir=tmpdir)
- self.tempfile_util = TempFileUtil(self.tmpdir)
- self._setup_logging()
-
- def get_exit_handler(self):
- def exit_handler(signum, frame):
- self.exit_process = True
- self._exit()
- return exit_handler
-
- def _exit(self, error=0):
- raise SystemExit(error)
-
- @classmethod
- def add_parser_options(cls, parser):
- """This should be overridden by each subcommand to add its own unique
- options to the parser
- """
- pass
-
- def load_options(self):
- """Compile arguments loaded from defaults, config files, and the command
- line into a usable set of options
- """
- # load the defaults defined by the component and the shared options
- opts = SoSOptions(arg_defaults=self._arg_defaults)
-
- for option in self.parser._actions:
- if option.default != '==SUPPRESS==':
- option.default = None
-
- # load values from cmdline
- cmdopts = SoSOptions().from_args(self.parser.parse_args())
- opts.merge(cmdopts)
-
- # load values from config file
- opts.update_from_conf(opts.config_file)
-
- return opts
-
- def _setup_logging(self):
- """Creates the log handler that shall be used by all components and any
- and all related bits to those components that need to log either to the
- console or to the log file for that run of sos.
- """
- # main soslog
- self.soslog = logging.getLogger('sos')
- self.soslog.setLevel(logging.DEBUG)
- self.sos_log_file = self.get_temp_file()
- flog = logging.StreamHandler(self.sos_log_file)
- flog.setFormatter(logging.Formatter(
- '%(asctime)s %(levelname)s: %(message)s'))
- flog.setLevel(logging.INFO)
- self.soslog.addHandler(flog)
-
- if not self.opts.quiet:
- console = logging.StreamHandler(sys.stdout)
- console.setFormatter(logging.Formatter('%(message)s'))
- if self.opts.verbosity and self.opts.verbosity > 1:
- console.setLevel(logging.DEBUG)
- flog.setLevel(logging.DEBUG)
- elif self.opts.verbosity and self.opts.verbosity > 0:
- console.setLevel(logging.INFO)
- flog.setLevel(logging.DEBUG)
- else:
- console.setLevel(logging.WARNING)
- self.soslog.addHandler(console)
- # log ERROR or higher logs to stderr instead
- console_err = logging.StreamHandler(sys.stderr)
- console_err.setFormatter(logging.Formatter('%(message)s'))
- console_err.setLevel(logging.ERROR)
- self.soslog.addHandler(console_err)
-
- # ui log
- self.ui_log = logging.getLogger('sos_ui')
- self.ui_log.setLevel(logging.INFO)
- self.sos_ui_log_file = self.get_temp_file()
- ui_fhandler = logging.StreamHandler(self.sos_ui_log_file)
- ui_fhandler.setFormatter(logging.Formatter(
- '%(asctime)s %(levelname)s: %(message)s'))
-
- self.ui_log.addHandler(ui_fhandler)
-
- if not self.opts.quiet:
- ui_console = logging.StreamHandler(sys.stdout)
- ui_console.setFormatter(logging.Formatter('%(message)s'))
- ui_console.setLevel(logging.INFO)
- self.ui_log.addHandler(ui_console)
-
- def get_temp_file(self):
- return self.tempfile_util.new()
+from sos.options import SosListOption
class SoS():
diff --git a/sos/component.py b/sos/component.py
new file mode 100644
index 00000000..16f77479
--- /dev/null
+++ b/sos/component.py
@@ -0,0 +1,171 @@
+# Copyright 2020 Red Hat, Inc.
+# Author: Jake Hunsaker <jhunsake@redhat.com>
+
+# This file is part of the sos project: https://github.com/sosreport/sos
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# version 2 of the GNU General Public License.
+#
+# See the LICENSE file in the source distribution for further information.
+
+import logging
+import tempfile
+import sys
+import sos.policies
+
+from argparse import SUPPRESS
+from sos.options import SoSOptions
+from sos.utilities import TempFileUtil
+
+
+class SoSComponent():
+ """Any sub-command that sos supports needs to subclass SoSComponent in
+ order to be properly supported by the sos binary.
+
+ This class contains the standardized entrypoint for subcommands, as well as
+ building out supported options from both globally shared option lists, and
+ options supported by that specific subcommand.
+
+ When sos initializes, it will load an unintialized instance of each class
+ found within one recursion of the module root directory that subclasses
+ SoSComponent.
+
+ If sos is able to match the user-specified subcommand to one that exists
+ locally, then that SoSComponent is initialized, logging is setup, and a
+ policy is loaded. From there, the component's execute() method takes over.
+
+ Added in 4.0
+ """
+
+ desc = 'unset'
+
+ arg_defaults = {}
+ configure_logging = True
+ load_policy = True
+
+ _arg_defaults = {
+ "config_file": '/etc/sos.conf',
+ "quiet": False,
+ "tmp_dir": '',
+ "sysroot": None,
+ "verbosity": 0
+ }
+
+ def __init__(self, parser, parsed_args, cmdline_args):
+ self.parser = parser
+ self.args = parsed_args
+ self.cmdline = cmdline_args
+ self.exit_process = False
+
+ try:
+ import signal
+ signal.signal(signal.SIGTERM, self.get_exit_handler())
+ except Exception:
+ pass
+
+ # update args from component's arg_defaults defintion
+ self._arg_defaults.update(self.arg_defaults)
+ self.opts = self.load_options()
+ if self.configure_logging:
+ tmpdir = self.opts.tmp_dir or tempfile.gettempdir()
+ self.tmpdir = tempfile.mkdtemp(prefix="sos.", dir=tmpdir)
+ self.tempfile_util = TempFileUtil(self.tmpdir)
+ self._setup_logging()
+
+ if self.load_policy:
+ try:
+ self.policy = sos.policies.load(sysroot=self.opts.sysroot)
+ except KeyboardInterrupt:
+ self._exit(0)
+ self._is_root = self.policy.is_root()
+
+ def get_exit_handler(self):
+ def exit_handler(signum, frame):
+ self.exit_process = True
+ self._exit()
+ return exit_handler
+
+ def _exit(self, error=0):
+ raise SystemExit(error)
+
+ @classmethod
+ def add_parser_options(cls, parser):
+ """This should be overridden by each subcommand to add its own unique
+ options to the parser
+ """
+ pass
+
+ def load_options(self):
+ """Compile arguments loaded from defaults, config files, and the command
+ line into a usable set of options
+ """
+ # load the defaults defined by the component and the shared options
+ opts = SoSOptions(arg_defaults=self._arg_defaults)
+
+ for option in self.parser._actions:
+ if option.default != SUPPRESS:
+ option.default = None
+
+ # load values from cmdline
+ cmdopts = SoSOptions().from_args(self.parser.parse_args())
+ opts.merge(cmdopts)
+
+ # load values from config file
+ opts.update_from_conf(opts.config_file)
+
+ return opts
+
+ def _setup_logging(self):
+ """Creates the log handler that shall be used by all components and any
+ and all related bits to those components that need to log either to the
+ console or to the log file for that run of sos.
+ """
+ # main soslog
+ self.soslog = logging.getLogger('sos')
+ self.soslog.setLevel(logging.DEBUG)
+ self.sos_log_file = self.get_temp_file()
+ flog = logging.StreamHandler(self.sos_log_file)
+ flog.setFormatter(logging.Formatter(
+ '%(asctime)s %(levelname)s: %(message)s'))
+ flog.setLevel(logging.INFO)
+ self.soslog.addHandler(flog)
+
+ if not self.opts.quiet:
+ console = logging.StreamHandler(sys.stdout)
+ console.setFormatter(logging.Formatter('%(message)s'))
+ if self.opts.verbosity and self.opts.verbosity > 1:
+ console.setLevel(logging.DEBUG)
+ flog.setLevel(logging.DEBUG)
+ elif self.opts.verbosity and self.opts.verbosity > 0:
+ console.setLevel(logging.INFO)
+ flog.setLevel(logging.DEBUG)
+ else:
+ console.setLevel(logging.WARNING)
+ self.soslog.addHandler(console)
+ # log ERROR or higher logs to stderr instead
+ console_err = logging.StreamHandler(sys.stderr)
+ console_err.setFormatter(logging.Formatter('%(message)s'))
+ console_err.setLevel(logging.ERROR)
+ self.soslog.addHandler(console_err)
+
+ # ui log
+ self.ui_log = logging.getLogger('sos_ui')
+ self.ui_log.setLevel(logging.INFO)
+ self.sos_ui_log_file = self.get_temp_file()
+ ui_fhandler = logging.StreamHandler(self.sos_ui_log_file)
+ ui_fhandler.setFormatter(logging.Formatter(
+ '%(asctime)s %(levelname)s: %(message)s'))
+
+ self.ui_log.addHandler(ui_fhandler)
+
+ if not self.opts.quiet:
+ ui_console = logging.StreamHandler(sys.stdout)
+ ui_console.setFormatter(logging.Formatter('%(message)s'))
+ ui_console.setLevel(logging.INFO)
+ self.ui_log.addHandler(ui_console)
+
+ def get_temp_file(self):
+ return self.tempfile_util.new()
+
+# vim: set et ts=4 sw=4 :