Merge "Bugfix: netperf_bottleneck execute failed because is_same_heat_context return...
[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
31 CONF = cfg.CONF
32 cli_opts = [
33     cfg.BoolOpt('debug',
34                 short='d',
35                 default=False,
36                 help='increase output verbosity to debug')
37 ]
38 CONF.register_cli_opts(cli_opts)
39
40 CONFIG_SEARCH_PATHS = [sys.prefix + "/etc/yardstick",
41                        "~/.yardstick",
42                        "/etc/yardstick"]
43
44
45 def find_config_files(path_list):
46     for path in path_list:
47         abspath = os.path.abspath(os.path.expanduser(path))
48         confname = abspath + "/yardstick.conf"
49         if os.path.isfile(confname):
50             return [confname]
51
52     return None
53
54
55 class YardstickCLI():
56     """Command-line interface to yardstick"""
57
58     # Command categories
59     categories = {
60         'task': task.TaskCommands,
61         'runner': runner.RunnerCommands,
62         'scenario': scenario.ScenarioCommands,
63         'testcase': testcase.TestcaseCommands,
64         'plugin': plugin.PluginCommands,
65         'env': env.EnvCommand
66     }
67
68     def __init__(self):
69         self.opts = []
70         self._version = 'yardstick version %s ' % \
71             get_distribution('yardstick').version
72
73     def _find_actions(self, subparsers, actions_module):
74         """find action methods"""
75         # Find action methods inside actions_module and
76         # add them to the command parser.
77         # The 'actions_module' argument may be a class
78         # or module. Action methods start with 'do_'
79         for attr in (a for a in dir(actions_module) if a.startswith('do_')):
80             command = attr[3:].replace('_', '-')
81             callback = getattr(actions_module, attr)
82             desc = callback.__doc__ or ''
83             arguments = getattr(callback, 'arguments', [])
84             subparser = subparsers.add_parser(
85                 command,
86                 description=desc
87             )
88             for (args, kwargs) in arguments:
89                 subparser.add_argument(*args, **kwargs)
90             subparser.set_defaults(func=callback)
91
92     def _add_command_parsers(self, categories, subparsers):
93         """add commands to command-line parser"""
94         for category in categories:
95             command_object = categories[category]()
96             desc = command_object.__doc__ or ''
97             subparser = subparsers.add_parser(
98                 category, description=desc,
99                 formatter_class=RawDescriptionHelpFormatter
100             )
101             subparser.set_defaults(command_object=command_object)
102             cmd_subparsers = subparser.add_subparsers(title='subcommands')
103             self._find_actions(cmd_subparsers, command_object)
104
105     def _register_cli_opt(self):
106
107         # register subcommands to parse additional command line arguments
108         def parser(subparsers):
109             self._add_command_parsers(YardstickCLI.categories, subparsers)
110
111         category_opt = cfg.SubCommandOpt("category",
112                                          title="Command categories",
113                                          help="Available categories",
114                                          handler=parser)
115         self._register_opt(category_opt)
116
117     def _register_opt(self, opt):
118
119         CONF.register_cli_opt(opt)
120         self.opts.append(opt)
121
122     def _load_cli_config(self, argv):
123
124         # load CLI args and config files
125         CONF(argv, project="yardstick", version=self._version,
126              default_config_files=find_config_files(CONFIG_SEARCH_PATHS))
127
128     def _handle_global_opts(self):
129
130         _init_logging()
131         if CONF.debug:
132             _LOG_STREAM_HDLR.setLevel(logging.DEBUG)
133
134     def _dispath_func_notask(self):
135
136         # dispatch to category parser
137         func = CONF.category.func
138         func(CONF.category)
139
140     def _dispath_func_task(self, task_id):
141
142         # dispatch to category parser
143         func = CONF.category.func
144         func(CONF.category, task_id=task_id)
145
146     def _clear_config_opts(self):
147
148         CONF.clear()
149         CONF.unregister_opts(self.opts)
150
151     def main(self, argv):    # pragma: no cover
152         """run the command line interface"""
153         try:
154             self._register_cli_opt()
155
156             self._load_cli_config(argv)
157
158             self._handle_global_opts()
159
160             self._dispath_func_notask()
161         finally:
162             self._clear_config_opts()
163
164     def api(self, argv, task_id):    # pragma: no cover
165         """run the api interface"""
166         try:
167             self._register_cli_opt()
168
169             self._load_cli_config(argv)
170
171             self._handle_global_opts()
172
173             self._dispath_func_task(task_id)
174         finally:
175             self._clear_config_opts()