Unified command execution and unit tests

- All arguments inits moved to own clases
- Added unified way to execute commands
- Unit test structure and very basic tests
- Command line script to test coverage

Change-Id: I10bc973776595779b563b84548d46367bcd0886f
Related-PROD: PROD-28199
diff --git a/cfg_checker/cfg_check.py b/cfg_checker/cfg_check.py
index 00e40d2..22125f6 100644
--- a/cfg_checker/cfg_check.py
+++ b/cfg_checker/cfg_check.py
@@ -1,38 +1,17 @@
-import argparse
 import os
 import sys
-import traceback
 from logging import DEBUG, INFO
 
+from cfg_checker.cli.command import execute_command
+from cfg_checker.cli.network import init_network_parser
+from cfg_checker.cli.package import init_package_parser
+from cfg_checker.cli.reclass import init_reclass_parser
 from cfg_checker.common import config, logger, logger_cli
-from cfg_checker.common.exception import CheckerException
-
+from cfg_checker.helpers.args_utils import MyParser
 
 pkg_dir = os.path.dirname(__file__)
 pkg_dir = os.path.normpath(pkg_dir)
 
-commands = {
-    'packages': ['report'],
-    'network': ['check', 'report'],
-    'reclass': ['list', 'diff']
-}
-
-
-class MyParser(argparse.ArgumentParser):
-    def error(self, message):
-        sys.stderr.write('Error: {0}\n\n'.format(message))
-        self.print_help()
-
-
-def help_message():
-    print"""
-    Please, use following examples to generate info reports:\n
-         cfg_checker packages report\n
-         cfg_checker network check\n
-         cfg_checker network report\n
-    """
-    return
-
 
 def config_check_entrypoint():
     """
@@ -44,19 +23,6 @@
     # Main entrypoint
     parser = MyParser(prog="# Mirantis Cloud configuration checker")
 
-    # Parsers (each parser can have own arguments)
-    # - subparsers (command)
-    #   |- pkg_parser
-    #   |  - pkg_subparsers (type)
-    #   |    - pkg_report_parser (default func - pkg_check)
-    #   |- net_parser
-    #   |  - net_subparsers (type)
-    #   |    - net_check_parser (default func - net_check)
-    #   |    - net_report_parser (default func - net_report)
-    #    - reclass_parser
-    #      - reclass_list (default func - reclass_list)
-    #      - reclass_compare (default func - reclass_diff)
-
     parser.add_argument(
         "-d",
         "--debug",
@@ -70,105 +36,34 @@
         help="Use sudo for getting salt creds"
     )
     subparsers = parser.add_subparsers(dest='command')
-    # packages
+
+    # package
     pkg_parser = subparsers.add_parser(
         'packages',
         help="Package versions check (Candidate vs Installed)"
     )
-    pkg_subparsers = pkg_parser.add_subparsers(dest='type')
-
-    pkg_report_parser = pkg_subparsers.add_parser(
-        'report',
-        help="Report package versions to HTML file"
-    )
-    pkg_report_parser.add_argument(
-        '--full',
-        action="store_true", default=False,
-        help="HTML report will have all of the packages, not just errors"
-    )
-    pkg_report_parser.add_argument(
-        '--html',
-        metavar='packages_html_filename',
-        help="HTML filename to save report"
-    )
-    pkg_report_parser.add_argument(
-        '--csv',
-        metavar='packages_csv_filename',
-        help="CSV filename to save report"
-    )
+    init_package_parser(pkg_parser)
 
     # networking
     net_parser = subparsers.add_parser(
         'network',
         help="Network infrastructure checks and reports"
     )
-    net_subparsers = net_parser.add_subparsers(dest='type')
-
-    net_check_parser = net_subparsers.add_parser(
-        'check',
-        help="Do network check and print the result"
-    )
-
-    net_check_parser.add_argument(
-        '--detailed',
-        action="store_true", default=False,
-        help="Print error details after summary"
-    )
-
-    net_report_parser = net_subparsers.add_parser(
-        'report',
-        help="Generate network check report"
-    )
-
-    net_report_parser.add_argument(
-        '--html',
-        metavar='network_html_filename',
-        help="HTML filename to save report"
-    )
+    init_network_parser(net_parser)
 
     # reclass
     reclass_parser = subparsers.add_parser(
         'reclass',
         help="Reclass related checks and reports"
     )
-    reclass_subparsers = reclass_parser.add_subparsers(dest='type')
-    reclass_list_parser = reclass_subparsers.add_parser(
-        'list',
-        help="List models available to compare"
-    )
-    reclass_list_parser.add_argument(
-        "-p",
-        "--models-path",
-        default="/srv/salt/",
-        help="Global path to search models in"
-    )
-
-    reclass_diff_parser = reclass_subparsers.add_parser(
-        'diff',
-        help="List models available to compare"
-    )
-    reclass_diff_parser.add_argument(
-        "--model1",
-        required=True,
-        help="Model A <path>. Model name is the folder name"
-    )
-    reclass_diff_parser.add_argument(
-        "--model2",
-        required=True,
-        help="Model B <path>. Model name is the folder name"
-    )
-    reclass_diff_parser.add_argument(
-        '--html',
-        metavar='reclass_html_filename',
-        help="HTML filename to save report"
-    )
+    init_reclass_parser(reclass_parser)
 
     # parse arguments
     try:
         args = parser.parse_args()
     except TypeError:
         logger_cli.info("\n# Please, check arguments")
-        return
+        sys.exit(0)
 
     # Pass externally configured values
     config.ssh_uses_sudo = args.sudo
@@ -179,51 +74,11 @@
     else:
         logger_cli.setLevel(INFO)
 
-    # Validate the commands
-    # check command
-    if args.command not in commands:
-        logger_cli.info("\n# Please, type a command listed above")
-        return
-    elif args.type not in commands[args.command]:
-        # check type
-        logger_cli.info(
-            "\n# Please, select '{}' command type listed above".format(
-                args.command
-            )
-        )
-        return
-    else:
-        # form function name to call
-        _method_name = "do_" + args.type
-        _target_module = __import__(
-            "cfg_checker.modules."+args.command,
-            fromlist=[""]
-        )
-        _method = getattr(_target_module, _method_name)
-
     # Execute the command
-    result = _method(args)
-
+    result = execute_command(args, args.command)
     logger.debug(result)
-
-
-def cli_main():
-    try:
-        config_check_entrypoint()
-    except CheckerException as e:
-        logger_cli.error("\nERROR: {}".format(
-            e.message
-        ))
-
-        exc_type, exc_value, exc_traceback = sys.exc_info()
-        logger_cli.debug("\n{}".format(
-            "".join(traceback.format_exception(
-                exc_type,
-                exc_value,
-                exc_traceback
-            ))
-        ))
+    sys.exit(result)
 
 
 if __name__ == '__main__':
-    cli_main()
+    config_check_entrypoint()