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