Merge "Yardstick Plugin: add support for ssh login using key"
[yardstick.git] / yardstick / cmd / cli.py
index ae7f3be..beaa187 100644 (file)
 Command-line interface to yardstick
 '''
 
-import argparse
 import logging
+import os
+import sys
 
 from pkg_resources import get_distribution
 from argparse import RawDescriptionHelpFormatter
+from oslo_config import cfg
 
+from yardstick import _init_logging, LOG
 from yardstick.cmd.commands import task
 from yardstick.cmd.commands import runner
 from yardstick.cmd.commands import scenario
+from yardstick.cmd.commands import testcase
+from yardstick.cmd.commands import plugin
+from yardstick.cmd.commands import env
+
+CONF = cfg.CONF
+cli_opts = [
+    cfg.BoolOpt('debug',
+                short='d',
+                default=False,
+                help='increase output verbosity to debug'),
+    cfg.BoolOpt('verbose',
+                short='v',
+                default=False,
+                help='increase output verbosity to info')
+]
+CONF.register_cli_opts(cli_opts)
+
+CONFIG_SEARCH_PATHS = [sys.prefix + "/etc/yardstick",
+                       "~/.yardstick",
+                       "/etc/yardstick"]
+
+
+def find_config_files(path_list):
+    for path in path_list:
+        abspath = os.path.abspath(os.path.expanduser(path))
+        confname = abspath + "/yardstick.conf"
+        if os.path.isfile(confname):
+            return [confname]
+
+    return None
 
 
 class YardstickCLI():
@@ -29,45 +62,17 @@ class YardstickCLI():
     categories = {
         'task': task.TaskCommands,
         'runner': runner.RunnerCommands,
-        'scenario': scenario.ScenarioCommands
+        'scenario': scenario.ScenarioCommands,
+        'testcase': testcase.TestcaseCommands,
+        'plugin': plugin.PluginCommands,
+        'env': env.EnvCommand
     }
 
     def __init__(self):
+        self.opts = []
         self._version = 'yardstick version %s ' % \
             get_distribution('yardstick').version
 
-    def _get_base_parser(self):
-        '''get base (top level) parser'''
-
-        parser = argparse.ArgumentParser(
-            prog='yardstick',
-            formatter_class=RawDescriptionHelpFormatter,
-            description=YardstickCLI.__doc__ or ''
-        )
-
-        # Global options
-
-        parser.add_argument(
-            "-V", "--version",
-            help="display version",
-            version=self._version,
-            action="version"
-        )
-
-        parser.add_argument(
-            "-d", "--debug",
-            help="increase output verbosity to debug",
-            action="store_true"
-        )
-
-        parser.add_argument(
-            "-v", "--verbose",
-            help="increase output verbosity to info",
-            action="store_true"
-        )
-
-        return parser
-
     def _find_actions(self, subparsers, actions_module):
         '''find action methods'''
         # Find action methods inside actions_module and
@@ -87,17 +92,10 @@ class YardstickCLI():
                 subparser.add_argument(*args, **kwargs)
             subparser.set_defaults(func=callback)
 
-    def _get_parser(self):
-        '''get a command-line parser'''
-        parser = self._get_base_parser()
-
-        subparsers = parser.add_subparsers(
-            title='subcommands',
-        )
-
-        # add subcommands
-        for category in YardstickCLI.categories:
-            command_object = YardstickCLI.categories[category]()
+    def _add_command_parsers(self, categories, subparsers):
+        '''add commands to command-line parser'''
+        for category in categories:
+            command_object = categories[category]()
             desc = command_object.__doc__ or ''
             subparser = subparsers.add_parser(
                 category, description=desc,
@@ -107,26 +105,77 @@ class YardstickCLI():
             cmd_subparsers = subparser.add_subparsers(title='subcommands')
             self._find_actions(cmd_subparsers, command_object)
 
-        return parser
+    def _register_cli_opt(self):
 
-    def main(self, argv):
-        '''run the command line interface'''
+        # register subcommands to parse additional command line arguments
+        def parser(subparsers):
+            self._add_command_parsers(YardstickCLI.categories, subparsers)
+
+        category_opt = cfg.SubCommandOpt("category",
+                                         title="Command categories",
+                                         help="Available categories",
+                                         handler=parser)
+        self._register_opt(category_opt)
+
+    def _register_opt(self, opt):
+
+        CONF.register_cli_opt(opt)
+        self.opts.append(opt)
+
+    def _load_cli_config(self, argv):
 
-        # get argument parser
-        parser = self._get_parser()
+        # load CLI args and config files
+        CONF(argv, project="yardstick", version=self._version,
+             default_config_files=find_config_files(CONFIG_SEARCH_PATHS))
 
-        # parse command-line
-        args = parser.parse_args(argv)
+    def _handle_global_opts(self):
 
-        # handle global opts
-        logger = logging.getLogger('yardstick')
-        logger.setLevel(logging.WARNING)
+        _init_logging()
+        if CONF.verbose:
+            LOG.setLevel(logging.INFO)
 
-        if args.verbose:
-            logger.setLevel(logging.INFO)
+        if CONF.debug:
+            LOG.setLevel(logging.DEBUG)
 
-        if args.debug:
-            logger.setLevel(logging.DEBUG)
+    def _dispath_func_notask(self):
 
         # dispatch to category parser
-        args.func(args)
+        func = CONF.category.func
+        func(CONF.category)
+
+    def _dispath_func_task(self, task_id):
+
+        # dispatch to category parser
+        func = CONF.category.func
+        func(CONF.category, task_id=task_id)
+
+    def _clear_config_opts(self):
+
+        CONF.clear()
+        CONF.unregister_opts(self.opts)
+
+    def main(self, argv):    # pragma: no cover
+        '''run the command line interface'''
+        try:
+            self._register_cli_opt()
+
+            self._load_cli_config(argv)
+
+            self._handle_global_opts()
+
+            self._dispath_func_notask()
+        finally:
+            self._clear_config_opts()
+
+    def api(self, argv, task_id):    # pragma: no cover
+        '''run the api interface'''
+        try:
+            self._register_cli_opt()
+
+            self._load_cli_config(argv)
+
+            self._handle_global_opts()
+
+            self._dispath_func_task(task_id)
+        finally:
+            self._clear_config_opts()