move flatten dict key to common utils
[yardstick.git] / yardstick / cmd / cli.py
1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 """
11 Command-line interface to yardstick
12 """
13
14 from __future__ import absolute_import
15 import logging
16 import os
17 import sys
18
19 from pkg_resources import get_distribution
20 from argparse import RawDescriptionHelpFormatter
21 from oslo_config import cfg
22
23 from yardstick import _init_logging, _LOG_STREAM_HDLR
24 from yardstick.cmd.commands import task
25 from yardstick.cmd.commands import runner
26 from yardstick.cmd.commands import scenario
27 from yardstick.cmd.commands import testcase
28 from yardstick.cmd.commands import plugin
29 from yardstick.cmd.commands import env
30 from yardstick.cmd.commands import report
31
32 CONF = cfg.CONF
33 cli_opts = [
34     cfg.BoolOpt('debug',
35                 short='d',
36                 default=False,
37                 help='increase output verbosity to debug')
38 ]
39 CONF.register_cli_opts(cli_opts)
40
41 CONFIG_SEARCH_PATHS = [sys.prefix + "/etc/yardstick",
42                        "~/.yardstick",
43                        "/etc/yardstick"]
44
45
46 def find_config_files(path_list):
47     for path in path_list:
48         abspath = os.path.abspath(os.path.expanduser(path))
49         confname = abspath + "/yardstick.conf"
50         if os.path.isfile(confname):
51             return [confname]
52
53     return None
54
55
56 class YardstickCLI():   # pragma: no cover
57     """Command-line interface to yardstick"""
58
59     # Command categories
60     categories = {
61         'task': task.TaskCommands,
62         'runner': runner.RunnerCommands,
63         'scenario': scenario.ScenarioCommands,
64         'testcase': testcase.TestcaseCommands,
65         'plugin': plugin.PluginCommands,
66         'env': env.EnvCommand,
67         'report': report.ReportCommands
68     }
69
70     def __init__(self):
71         self.opts = []
72         self._version = 'yardstick version %s ' % \
73             get_distribution('yardstick').version
74
75     def _find_actions(self, subparsers, actions_module):
76         """find action methods"""
77         # Find action methods inside actions_module and
78         # add them to the command parser.
79         # The 'actions_module' argument may be a class
80         # or module. Action methods start with 'do_'
81         for attr in (a for a in dir(actions_module) if a.startswith('do_')):
82             command = attr[3:].replace('_', '-')
83             callback = getattr(actions_module, attr)
84             desc = callback.__doc__ or ''
85             arguments = getattr(callback, 'arguments', [])
86             subparser = subparsers.add_parser(
87                 command,
88                 description=desc
89             )
90             for (args, kwargs) in arguments:
91                 subparser.add_argument(*args, **kwargs)
92             subparser.set_defaults(func=callback)
93
94     def _add_command_parsers(self, categories, subparsers):
95         """add commands to command-line parser"""
96         for category in categories:
97             command_object = categories[category]()
98             desc = command_object.__doc__ or ''
99             subparser = subparsers.add_parser(
100                 category, description=desc,
101                 formatter_class=RawDescriptionHelpFormatter
102             )
103             subparser.set_defaults(command_object=command_object)
104             cmd_subparsers = subparser.add_subparsers(title='subcommands')
105             self._find_actions(cmd_subparsers, command_object)
106
107     def _register_cli_opt(self):
108
109         # register subcommands to parse additional command line arguments
110         def parser(subparsers):
111             self._add_command_parsers(YardstickCLI.categories, subparsers)
112
113         category_opt = cfg.SubCommandOpt("category",
114                                          title="Command categories",
115                                          help="Available categories",
116                                          handler=parser)
117         self._register_opt(category_opt)
118
119     def _register_opt(self, opt):
120
121         CONF.register_cli_opt(opt)
122         self.opts.append(opt)
123
124     def _load_cli_config(self, argv):
125
126         # load CLI args and config files
127         CONF(argv, project="yardstick", version=self._version,
128              default_config_files=find_config_files(CONFIG_SEARCH_PATHS))
129
130     def _handle_global_opts(self):
131
132         _init_logging()
133         if CONF.debug:
134             _LOG_STREAM_HDLR.setLevel(logging.DEBUG)
135
136     def _dispath_func_notask(self):
137
138         # dispatch to category parser
139         func = CONF.category.func
140         func(CONF.category)
141
142     def _dispath_func_task(self, task_id):
143
144         # dispatch to category parser
145         func = CONF.category.func
146         func(CONF.category, task_id=task_id)
147
148     def _clear_config_opts(self):
149
150         CONF.clear()
151         CONF.unregister_opts(self.opts)
152
153     def main(self, argv):    # pragma: no cover
154         """run the command line interface"""
155         try:
156             self._register_cli_opt()
157
158             self._load_cli_config(argv)
159
160             self._handle_global_opts()
161
162             self._dispath_func_notask()
163         finally:
164             self._clear_config_opts()
165
166     def api(self, argv, task_id):    # pragma: no cover
167         """run the api interface"""
168         try:
169             self._register_cli_opt()
170
171             self._load_cli_config(argv)
172
173             self._handle_global_opts()
174
175             self._dispath_func_task(task_id)
176         finally:
177             self._clear_config_opts()