Adding simple cmdline to run the Network service testcases
[yardstick.git] / yardstick / cmd / NSBperf.py
1 #!/usr/bin/env python
2 # Copyright (c) 2016-2017 Intel Corporation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #      http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16
17 """NSBPERF main script.
18 """
19
20 from __future__ import absolute_import
21 from __future__ import print_function
22 import os
23 import argparse
24 import json
25 import subprocess
26 import signal
27
28 CLI_PATH = os.path.dirname(os.path.realpath(__file__))
29 REPO_PATH = os.path.abspath(os.path.join(CLI_PATH, os.pardir))
30 PYTHONPATH = os.environ.get("PYTHONPATH", False)
31 VIRTUAL_ENV = os.environ.get("VIRTUAL_ENV", False)
32
33 if not PYTHONPATH or not VIRTUAL_ENV:
34     print("Please setup env PYTHONPATH & VIRTUAL_ENV environment varaible.")
35     raise SystemExit(1)
36
37
38 def handler():
39     """ Capture ctrl+c and exit cli """
40     subprocess.call(["pkill", "-9", "yardstick"])
41     raise SystemExit(1)
42
43 signal.signal(signal.SIGINT, handler)
44
45
46 class YardstickNSCli(object):
47     """ This class handles yardstick network serivce testing """
48
49     def __init__(self):
50         super(YardstickNSCli, self).__init__()
51
52     @classmethod
53     def validate_input(cls, choice, choice_len):
54         """ Validate user inputs """
55         if not str(choice):
56             return 1
57
58         choice = int(choice)
59         if not 1 <= choice <= choice_len:
60             print("\nInvalid wrong choice...")
61             raw_input("Press Enter to continue...")
62             return 1
63         subprocess.call(['clear'])
64         return 0
65
66     @classmethod
67     def parse_arguments(cls):
68         """
69         Parse command line arguments.
70         """
71         parser = \
72             argparse.ArgumentParser(
73                 prog=__file__,
74                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
75         parser.add_argument('--version', action='version',
76                             version='%(prog)s 0.1')
77         parser.add_argument('--list', '--list-tests', action='store_true',
78                             help='list all tests and exit')
79         parser.add_argument('--list-vnfs', action='store_true',
80                             help='list all system vnfs and exit')
81
82         group = parser.add_argument_group('test selection options')
83         group.add_argument('--vnf', help='vnf to use')
84         group.add_argument('--test', help='test in use')
85
86         args = vars(parser.parse_args())
87
88         return args
89
90     @classmethod
91     def generate_kpi_results(cls, tkey, tgen):
92         """ Generate report for vnf & traffic generator kpis """
93         if tgen:
94             print("\n%s stats" % tkey)
95             print("----------------------------")
96             for key, value in tgen.items():
97                 if key != "collect_stats":
98                     print(json.dumps({key: value}, indent=2))
99
100     @classmethod
101     def generate_nfvi_results(cls, nfvi):
102         """ Generate report for vnf & traffic generator kpis """
103         if nfvi:
104             nfvi_kpi = {k: v for k, v in nfvi.items() if k == 'collect_stats'}
105             if nfvi_kpi:
106                 print("\nNFVi stats")
107                 print("----------------------------")
108                 for key, value in nfvi_kpi.items():
109                     print(json.dumps({key: value}, indent=2))
110
111     def generate_final_report(self, test_case):
112         """ Function will check if partial test results are available
113         and generates final report in rst format.
114 """
115
116         report_caption = '{}\n{} ({})\n{}\n\n'.format(
117             '================================================================',
118             'Performance report for',
119             os.path.splitext(test_case)[0].upper(),
120             '================================================================')
121         print(report_caption)
122         if os.path.isfile("/tmp/yardstick.out"):
123             lines = []
124             with open("/tmp/yardstick.out") as infile:
125                 lines = infile.readlines()
126
127             if lines:
128                 tc_res = json.loads(lines.pop(len(lines) - 1))
129                 for key, value in tc_res["benchmark"]["data"].items():
130                     self.generate_kpi_results(key, value)
131                     self.generate_nfvi_results(value)
132
133     @classmethod
134     def handle_list_options(cls, args, test_path):
135         """ Process --list cli arguments if needed
136
137         :param args: A dictionary with all CLI arguments
138         """
139         if args['list_vnfs']:
140             vnfs = os.listdir(test_path)
141             print("VNF :")
142             print("================")
143             for index, vnf in enumerate(vnfs, 1):
144                 print((' %-2s %s' % ('%s:' % str(index), vnf)))
145             raise SystemExit(0)
146
147         if args['list']:
148             vnfs = os.listdir(test_path)
149
150             print("Available Tests:")
151             print("*****************")
152             for vnf in vnfs:
153                 testcases = os.listdir(test_path + vnf)
154                 print(("VNF :(%s)" % vnf))
155                 print("================")
156                 for testcase in [tc for tc in testcases if "tc" in tc]:
157                     print('%s' % testcase)
158                 print(os.linesep)
159             raise SystemExit(0)
160
161     @classmethod
162     def terminate_if_less_options(cls, args):
163         """ terminate cli if cmdline options is invalid """
164         if not (args["vnf"] and args["test"]):
165             print("CLI needs option, make sure to pass vnf, test")
166             print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
167             raise SystemExit(1)
168
169     def run_test(self, args, test_path):
170         """ run requested test """
171         try:
172             vnf = args.get("vnf", "")
173             test = args.get("test", "")
174
175             vnf_dir = test_path + os.sep + vnf
176             if not os.path.exists(vnf_dir):
177                 raise ValueError("'%s', vnf not supported." % vnf)
178
179             testcases = [tc for tc in os.listdir(vnf_dir) if "tc" in tc]
180             subtest = set([test]).issubset(testcases)
181             if not subtest:
182                 raise ValueError("'%s', testcase not supported." % test)
183
184             os.chdir(vnf_dir)
185             # fixme: Use REST APIs to initiate testcases
186             subprocess.check_output(["yardstick", "--debug",
187                                      "task", "start", test])
188             self.generate_final_report(test)
189         except (IOError, ValueError):
190             print("Value/I/O error...")
191         except BaseException:
192             print("Test failed. Please verify test inputs & re-run the test..")
193             print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
194
195     def main(self):
196         """Main function.
197         """
198         test_path = os.path.join(REPO_PATH, "../samples/vnf_samples/nsut/")
199         os.chdir(os.path.join(REPO_PATH, "../"))
200         args = self.parse_arguments()
201
202         # if required, handle list-* operations
203         self.handle_list_options(args, test_path)
204
205         # check for input params
206         self.terminate_if_less_options(args)
207
208         # run test
209         self.run_test(args, test_path)
210
211 if __name__ == "__main__":
212     NS_CLI = YardstickNSCli()
213     NS_CLI.main()