summaryrefslogtreecommitdiff
path: root/contrib/python/cmd/pydman.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/python/cmd/pydman.py')
-rwxr-xr-xcontrib/python/cmd/pydman.py248
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)