blob: 778cdb14427fb095e58d10f70e530b5d309bb0bd [file] [log] [blame]
Alex0989ecf2022-03-29 13:43:21 -05001# Author: Alex Savatieiev (osavatieiev@mirantis.com; a.savex@gmail.com)
2# Copyright 2019-2022 Mirantis, Inc.
Alexbab1efe2019-04-23 18:51:23 -05003import pkgutil
Alex265f45e2019-04-23 18:51:23 -05004import sys
5import traceback
6
Alex9a4ad212020-10-01 18:04:25 -05007from cfg_checker.cli.arguments import add_global_arguments
8from cfg_checker.common import logger, logger_cli
9from cfg_checker.common.exception import CheckerException, \
10 CommandNotSupportedException
11from cfg_checker.common.settings import CheckerConfiguration
Alexbab1efe2019-04-23 18:51:23 -050012from cfg_checker.helpers.args_utils import MyParser
Alex265f45e2019-04-23 18:51:23 -050013
Alexbab1efe2019-04-23 18:51:23 -050014main_pkg_name = __name__.split('.')[0]
15mods_package_name = "modules"
16mods_import_path = main_pkg_name + '.' + mods_package_name
17mods_prefix = mods_import_path + '.'
Alex265f45e2019-04-23 18:51:23 -050018
Alexbab1efe2019-04-23 18:51:23 -050019commands = {}
Alex9a4ad212020-10-01 18:04:25 -050020supports = {}
Alexac2a2732020-09-11 11:00:26 -050021parsers_inits = {}
Alexbab1efe2019-04-23 18:51:23 -050022parsers = {}
23helps = {}
24# Pure dynamic magic, loading all 'do_*' methods from available modules
25_m = __import__(mods_import_path, fromlist=[main_pkg_name])
26for _imp, modName, isMod in pkgutil.iter_modules(_m.__path__, mods_prefix):
27 # iterate all packages, add to dict
28 if isMod:
29 # load module
30 _p = _imp.find_module(modName).load_module(modName)
31 # create a shortname
32 mod_name = modName.split('.')[-1]
33 # A package! Create it and add commands
34 commands[mod_name] = \
35 [_n[3:] for _n in dir(_p) if _n.startswith("do_")]
Alex9a4ad212020-10-01 18:04:25 -050036 supports[mod_name] = _p.supported_envs
Alexac2a2732020-09-11 11:00:26 -050037 parsers_inits[mod_name] = getattr(_p, 'init_parser')
38 parsers[mod_name] = {}
Alexbab1efe2019-04-23 18:51:23 -050039 helps[mod_name] = getattr(_p, 'command_help')
Alex265f45e2019-04-23 18:51:23 -050040
41
Alex9a4ad212020-10-01 18:04:25 -050042def execute_command(args, command, config):
Alex265f45e2019-04-23 18:51:23 -050043 # Validate the commands
Alexcf91b182019-05-31 11:57:07 -050044 # check commands
Alexac2a2732020-09-11 11:00:26 -050045 if command not in commands:
Alexac2a2732020-09-11 11:00:26 -050046 logger_cli.info("\n# Please, type a command listed above")
47 return 1
Alexcf91b182019-05-31 11:57:07 -050048 if not hasattr(args, 'type') or not args.type:
Alexac2a2732020-09-11 11:00:26 -050049 parsers[command].print_help()
Alexcf91b182019-05-31 11:57:07 -050050 logger_cli.info("\n# Please, type a command listed above")
Alex3bc95f62020-03-05 17:00:04 -060051 return 1
Alexd0391d42019-05-21 18:48:55 -050052 _type = args.type.replace("-", "_") if "-" in args.type else args.type
Alexac2a2732020-09-11 11:00:26 -050053 if _type not in commands[command]:
Alex265f45e2019-04-23 18:51:23 -050054 # check type
55 logger_cli.info(
56 "\n# Please, select '{}' command type listed above".format(
57 command
58 )
59 )
Alex3bc95f62020-03-05 17:00:04 -060060 return 1
Alex265f45e2019-04-23 18:51:23 -050061 else:
Alex9a4ad212020-10-01 18:04:25 -050062 # check if command is supported
63 if len(
64 set(supports[command]).intersection(set(config.detected_envs))
65 ) < 1:
66 raise CommandNotSupportedException(
67 "'{}' is not supported on any of the currently "
68 "detected environments: {}".format(
69 command,
70 ",".join(config.detected_envs)
71 )
72 )
73 return 1
74
Alex265f45e2019-04-23 18:51:23 -050075 # form function name to call
Alexd0391d42019-05-21 18:48:55 -050076 _method_name = "do_" + _type
Alex265f45e2019-04-23 18:51:23 -050077 _target_module = __import__(
Alexbab1efe2019-04-23 18:51:23 -050078 mods_prefix + command,
Alex265f45e2019-04-23 18:51:23 -050079 fromlist=[""]
80 )
81 _method = getattr(_target_module, _method_name)
82
83 # Execute the command
84 try:
Alex9a4ad212020-10-01 18:04:25 -050085 # Compatibility between entrypoints
86 if not hasattr(args, 'command'):
87 args.command = command
88 _method(args, config)
Alex265f45e2019-04-23 18:51:23 -050089 return 0
Alex9a4ad212020-10-01 18:04:25 -050090 except CommandNotSupportedException as e:
91 logger_cli.error("\n{}".format(e.message))
92 return 1
Alex265f45e2019-04-23 18:51:23 -050093 except CheckerException as e:
Alex9a4ad212020-10-01 18:04:25 -050094 logger_cli.error("\n{}".format(e.message))
Alex265f45e2019-04-23 18:51:23 -050095
96 exc_type, exc_value, exc_traceback = sys.exc_info()
97 logger_cli.debug("\n{}".format(
98 "".join(traceback.format_exception(
99 exc_type,
100 exc_value,
101 exc_traceback
102 ))
103 ))
104 return 1
Alexbab1efe2019-04-23 18:51:23 -0500105
106
107def cli_command(_title, _name):
108 my_parser = MyParser(_title)
Alexac2a2732020-09-11 11:00:26 -0500109 parsers[_name] = parsers_inits[_name](my_parser)
Alexbab1efe2019-04-23 18:51:23 -0500110
111 # parse arguments
112 try:
Alex9a4ad212020-10-01 18:04:25 -0500113 add_global_arguments(my_parser)
Alexd0391d42019-05-21 18:48:55 -0500114 args, unknown = my_parser.parse_known_args()
Alexbab1efe2019-04-23 18:51:23 -0500115 except TypeError:
116 logger_cli.info("\n# Please, check arguments")
Alex3bc95f62020-03-05 17:00:04 -0600117 sys.exit(1)
Alexbab1efe2019-04-23 18:51:23 -0500118
Alexd0391d42019-05-21 18:48:55 -0500119 if unknown:
120 logger_cli.error(
121 "# Unexpected arguments: {}".format(
122 ", ".join(["'{}'".format(a) for a in unknown])
123 )
124 )
125 sys.exit(1)
126
Alex9a4ad212020-10-01 18:04:25 -0500127 # Init the config
128 config = CheckerConfiguration(args)
129
Alexbab1efe2019-04-23 18:51:23 -0500130 # force use of sudo
131 config.ssh_uses_sudo = True
132
133 # Execute the command
Alex9a4ad212020-10-01 18:04:25 -0500134 try:
135 result = execute_command(args, _name, config)
136 logger.debug(result)
137 except CommandNotSupportedException as e:
138 logger_cli.error("\nERROR: {}".format(
139 e.message
140 ))
Alexbab1efe2019-04-23 18:51:23 -0500141 sys.exit(result)