diff options
Diffstat (limited to 'contrib/python/cmd/pydman.py')
-rwxr-xr-x | contrib/python/cmd/pydman.py | 248 |
1 files changed, 0 insertions, 248 deletions
diff --git a/contrib/python/cmd/pydman.py b/contrib/python/cmd/pydman.py deleted file mode 100755 index 5008c706d..000000000 --- a/contrib/python/cmd/pydman.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env python3 -"""Remote podman client.""" - -import argparse -import curses -import getpass -import inspect -import logging -import os -import sys - -import pkg_resources - -import lib.actions -import pytoml - -assert lib.actions # silence pyflakes - -# TODO: setup.py and obtain __version__ from rpm.spec -try: - __version__ = pkg_resources.get_distribution('pydman').version -except Exception: - __version__ = '0.0.0' - - -class HelpFormatter(argparse.RawDescriptionHelpFormatter): - """Set help width to screen size.""" - - def __init__(self, *args, **kwargs): - """Construct HelpFormatter using screen width.""" - if 'width' not in kwargs: - kwargs['width'] = 80 - try: - height, width = curses.initscr().getmaxyx() - kwargs['width'] = width - finally: - curses.endwin() - super().__init__(*args, **kwargs) - - -class PodmanArgumentParser(argparse.ArgumentParser): - """Default remote podman configuration.""" - - def __init__(self, **kwargs): - """Construct the parser.""" - kwargs['add_help'] = True - kwargs['allow_abbrev'] = True - kwargs['description'] = __doc__ - kwargs['formatter_class'] = HelpFormatter - - super().__init__(**kwargs) - - def initialize_parser(self): - """Initialize parser without causing recursion meltdown.""" - self.add_argument( - '--version', - action='version', - version='%(prog)s v. ' + __version__) - self.add_argument( - '--log-level', - choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], - default='INFO', - type=str.upper, - help='set logging level for events. (default: %(default)s)', - ) - self.add_argument( - '--run-dir', - help=('directory to place local socket bindings.' - ' (default: XDG_RUNTIME_DIR)')) - self.add_argument( - '--user', - help=('Authenicating user on remote host.' - ' (default: {})').format(getpass.getuser())) - self.add_argument( - '--host', help='name of remote host. (default: None)') - self.add_argument( - '--remote-socket-path', - help=('path of podman socket on remote host' - ' (default: /run/podman/io.projectatomic.podman)')) - self.add_argument( - '--identity-file', - help=('path to ssh identity file. (default: ~/.ssh/id_rsa)')) - self.add_argument( - '--config', - default='/etc/containers/podman_client.conf', - dest='config_file', - help='path of configuration file. (default: %(default)s)') - - actions_parser = self.add_subparsers( - dest='subparser_name', help='actions') - - for name, obj in inspect.getmembers( - sys.modules['lib.actions'], - lambda member: inspect.isclass(member)): - if hasattr(obj, 'subparser'): - try: - obj.subparser(actions_parser) - except NameError as e: - logging.critical(e) - logging.warning( - 'See subparser configuration for Class "{}"'.format( - name)) - sys.exit(3) - - def parse_args(self, args=None, namespace=None): - """Parse command line arguments, backed by env var and config_file.""" - self.initialize_parser() - cooked = super().parse_args(args, namespace) - return self.resolve_configuration(cooked) - - def resolve_configuration(self, args): - """Find and fill in any arguments not passed on command line.""" - try: - # Configuration file optionall, arguments may be provided elsewhere - with open(args.config_file, 'r') as stream: - config = pytoml.load(stream) - except OSError: - logging.info( - 'Failed to read: {}'.format(args.config_file), - exc_info=args.log_level == logging.DEBUG) - config = {'default': {}} - else: - if 'default' not in config: - config['default'] = {} - - def resolve(name, value): - if value: - setattr(args, name, value) - return value - self.error('Required argument "%s" is not configured.' % name) - - xdg = os.path.join(os.environ['XDG_RUNTIME_DIR'], 'podman') \ - if os.environ.get('XDG_RUNTIME_DIR') else None - - resolve( - 'run_dir', - getattr(args, 'run_dir') - or os.environ.get('RUN_DIR') - or config['default'].get('run_dir') - or xdg - or '/tmp/podman' if os.path.isdir('/tmp') else None - ) # yapf: disable - - args.local_socket_path = os.path.join(args.run_dir, "podman.socket") - - resolve( - 'host', - getattr(args, 'host') - or os.environ.get('HOST') - or config['default'].get('host') - ) # yapf:disable - - resolve( - 'user', - getattr(args, 'user') - or os.environ.get('USER') - or config['default'].get('user') - or getpass.getuser() - ) # yapf:disable - - resolve( - 'remote_socket_path', - getattr(args, 'remote_socket_path') - or os.environ.get('REMOTE_SOCKET_PATH') - or config['default'].get('remote_socket_path') - or '/run/podman/io.projectatomic.podman' - ) # yapf:disable - - resolve( - 'identity_file', - getattr(args, 'identity_file') - or os.environ.get('IDENTITY_FILE') - or config['default'].get('identity_file') - or os.path.expanduser('~{}/.ssh/id_rsa'.format(args.user)) - ) # yapf:disable - - args.local_uri = "unix:{}".format(args.local_socket_path) - args.remote_uri = "ssh://{}@{}{}".format(args.user, args.host, - args.remote_socket_path) - return args - - def exit(self, status=0, message=None): - """Capture message and route to logger.""" - if message: - log = logging.info if status == 0 else logging.error - log(message) - super().exit(status) - - def error(self, message): - """Capture message and route to logger.""" - logging.error('{}: {}'.format(self.prog, message)) - logging.error("Try '{} --help' for more information.".format( - self.prog)) - super().exit(2) - - -if __name__ == '__main__': - # Setup logging so we use stderr and can change logging level later - # Do it now before there is any chance of a default setup. - log = logging.getLogger() - fmt = logging.Formatter('%(asctime)s | %(levelname)-8s | %(message)s', - '%Y-%m-%d %H:%M:%S %Z') - stderr = logging.StreamHandler(stream=sys.stderr) - stderr.setFormatter(fmt) - log.addHandler(stderr) - log.setLevel(logging.INFO) - - parser = PodmanArgumentParser() - args = parser.parse_args() - - log.setLevel(args.log_level) - logging.debug('Logging initialized at level {}'.format( - logging.getLevelName(logging.getLogger().getEffectiveLevel()))) - - def istraceback(): - """Add traceback when logging events.""" - return log.getEffectiveLevel() == logging.DEBUG - - try: - if not os.path.exists(args.run_dir): - os.makedirs(args.run_dir) - except PermissionError as e: - logging.critical(e, exc_info=istraceback()) - sys.exit(6) - - # Klass(args).method() are setup by the sub-command's parser - returncode = None - try: - obj = args.klass(args) - except Exception as e: - logging.critical(repr(e), exc_info=istraceback()) - logging.warning('See subparser "{}" configuration.'.format( - args.subparser_name)) - sys.exit(5) - - try: - returncode = getattr(obj, args.method)() - except AttributeError as e: - logging.critical(e, exc_info=istraceback()) - logging.warning('See subparser "{}" configuration.'.format( - args.subparser_name)) - returncode = 3 - except (ConnectionResetError, TimeoutError) as e: - logging.critical(e, exc_info=istraceback()) - logging.info('Review connection arguments for correctness.') - returncode = 4 - - sys.exit(0 if returncode is None else returncode) |