ee8d1c529c9ffaf893978270b9d6a1f6d39fcd18
[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 import logging
15 import os
16 import sys
17
18 from pkg_resources import get_distribution
19 from argparse import RawDescriptionHelpFormatter
20 from oslo_config import cfg
21
22 from yardstick.cmd.commands import task
23 from yardstick.cmd.commands import runner
24 from yardstick.cmd.commands import scenario
25 from yardstick.cmd.commands import testcase
26 from yardstick.cmd.commands import plugin
27
28 CONF = cfg.CONF
29 cli_opts = [
30     cfg.BoolOpt('debug',
31                 short='d',
32                 default=False,
33                 help='increase output verbosity to debug'),
34     cfg.BoolOpt('verbose',
35                 short='v',
36                 default=False,
37                 help='increase output verbosity to info')
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():
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     }
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         # handle global opts
131         logger = logging.getLogger('yardstick')
132         logger.setLevel(logging.WARNING)
133
134         if CONF.verbose:
135             logger.setLevel(logging.INFO)
136
137         if CONF.debug:
138             logger.setLevel(logging.DEBUG)
139
140     def _dispath_func_notask(self):
141
142         # dispatch to category parser
143         func = CONF.category.func
144         func(CONF.category)
145
146     def _dispath_func_task(self, task_id):
147
148         # dispatch to category parser
149         func = CONF.category.func
150         func(CONF.category, task_id=task_id)
151
152     def _clear_config_opts(self):
153
154         CONF.clear()
155         CONF.unregister_opts(self.opts)
156
157     def main(self, argv):    # pragma: no cover
158         '''run the command line interface'''
159         self._register_cli_opt()
160
161         self._load_cli_config(argv)
162
163         self._handle_global_opts()
164
165         self._dispath_func_notask()
166
167         self._clear_config_opts()
168
169     def api(self, argv, task_id):    # pragma: no cover
170         '''run the api interface'''
171         self._register_cli_opt()
172
173         self._load_cli_config(argv)
174
175         self._handle_global_opts()
176
177         self._dispath_func_task(task_id)
178
179         self._clear_config_opts()