3a6d604cd4cd694e863f91ae64b45ee2434b3c5e
[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 from oslo_serialization import jsonutils
28
29 from six.moves import input
30
31 CLI_PATH = os.path.dirname(os.path.realpath(__file__))
32 REPO_PATH = os.path.abspath(os.path.join(CLI_PATH, os.pardir))
33 PYTHONPATH = os.environ.get("PYTHONPATH", False)
34 VIRTUAL_ENV = os.environ.get("VIRTUAL_ENV", False)
35
36
37 if not PYTHONPATH or not VIRTUAL_ENV:
38     print("Please setup env PYTHONPATH & VIRTUAL_ENV environment varaible.")
39     raise SystemExit(1)
40
41
42 def handler():
43     """ Capture ctrl+c and exit cli """
44     subprocess.call(["pkill", "-9", "yardstick"])
45     raise SystemExit(1)
46
47 signal.signal(signal.SIGINT, handler)
48
49
50 class YardstickNSCli(object):
51     """ This class handles yardstick network serivce testing """
52
53     def __init__(self):
54         super(YardstickNSCli, self).__init__()
55
56     @classmethod
57     def validate_input(cls, choice, choice_len):
58         """ Validate user inputs """
59         if not str(choice):
60             return 1
61
62         choice = int(choice)
63         if not 1 <= choice <= choice_len:
64             print("\nInvalid wrong choice...")
65             input("Press Enter to continue...")
66             return 1
67         subprocess.call(['clear'])
68         return 0
69
70     @classmethod
71     def parse_arguments(cls):
72         """
73         Parse command line arguments.
74         """
75         parser = \
76             argparse.ArgumentParser(
77                 prog=__file__,
78                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
79         parser.add_argument('--version', action='version',
80                             version='%(prog)s 0.1')
81         parser.add_argument('--list', '--list-tests', action='store_true',
82                             help='list all tests and exit')
83         parser.add_argument('--list-vnfs', action='store_true',
84                             help='list all system vnfs and exit')
85
86         group = parser.add_argument_group('test selection options')
87         group.add_argument('--vnf', help='vnf to use')
88         group.add_argument('--test', help='test in use')
89
90         args = vars(parser.parse_args())
91
92         return args
93
94     @classmethod
95     def generate_kpi_results(cls, tkey, tgen):
96         """ Generate report for vnf & traffic generator kpis """
97         if tgen:
98             print("\n%s stats" % tkey)
99             print("----------------------------")
100             for key, value in tgen.items():
101                 if key != "collect_stats":
102                     print(json.dumps({key: value}, indent=2))
103
104     @classmethod
105     def generate_nfvi_results(cls, nfvi):
106         """ Generate report for vnf & traffic generator kpis """
107         if nfvi:
108             nfvi_kpi = {k: v for k, v in nfvi.items() if k == 'collect_stats'}
109             if nfvi_kpi:
110                 print("\nNFVi stats")
111                 print("----------------------------")
112                 for key, value in nfvi_kpi.items():
113                     print(json.dumps({key: value}, indent=2))
114
115     def generate_final_report(self, test_case):
116         """ Function will check if partial test results are available
117         and generates final report in rst format.
118         """
119
120         tc_name = os.path.splitext(test_case)[0]
121         report_caption = '{}\n{} ({})\n{}\n\n'.format(
122             '================================================================',
123             'Performance report for', tc_name.upper(),
124             '================================================================')
125         print(report_caption)
126         if os.path.isfile("/tmp/yardstick.out"):
127             lines = []
128             with open("/tmp/yardstick.out") as infile:
129                 lines = jsonutils.load(infile)
130
131             if lines:
132                 lines = \
133                     lines['result']["testcases"][tc_name]["tc_data"]
134                 tc_res = lines.pop(len(lines) - 1)
135                 for key, value in tc_res["data"].items():
136                     self.generate_kpi_results(key, value)
137                     self.generate_nfvi_results(value)
138
139     @classmethod
140     def handle_list_options(cls, args, test_path):
141         """ Process --list cli arguments if needed
142
143         :param args: A dictionary with all CLI arguments
144         """
145         if args['list_vnfs']:
146             vnfs = os.listdir(test_path)
147             print("VNF :")
148             print("================")
149             for index, vnf in enumerate(vnfs, 1):
150                 print((' %-2s %s' % ('%s:' % str(index), vnf)))
151             raise SystemExit(0)
152
153         if args['list']:
154             vnfs = os.listdir(test_path)
155
156             print("Available Tests:")
157             print("*****************")
158             for vnf in vnfs:
159                 testcases = os.listdir(test_path + vnf)
160                 print(("VNF :(%s)" % vnf))
161                 print("================")
162                 for testcase in [tc for tc in testcases if "tc_" in tc]:
163                     print('%s' % testcase)
164                 print(os.linesep)
165             raise SystemExit(0)
166
167     @classmethod
168     def terminate_if_less_options(cls, args):
169         """ terminate cli if cmdline options is invalid """
170         if not (args["vnf"] and args["test"]):
171             print("CLI needs option, make sure to pass vnf, test")
172             print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
173             raise SystemExit(1)
174
175     def run_test(self, args, test_path):
176         """ run requested test """
177         try:
178             vnf = args.get("vnf", "")
179             test = args.get("test", "")
180
181             vnf_dir = test_path + os.sep + vnf
182             if not os.path.exists(vnf_dir):
183                 raise ValueError("'%s', vnf not supported." % vnf)
184
185             testcases = [tc for tc in os.listdir(vnf_dir) if "tc" in tc]
186             subtest = set([test]).issubset(testcases)
187             if not subtest:
188                 raise ValueError("'%s', testcase not supported." % test)
189
190             os.chdir(vnf_dir)
191             # fixme: Use REST APIs to initiate testcases
192             subprocess.check_output(["yardstick", "--debug",
193                                      "task", "start", test])
194             self.generate_final_report(test)
195         except (IOError, ValueError):
196             print("Value/I/O error...")
197         except BaseException:
198             print("Test failed. Please verify test inputs & re-run the test..")
199             print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
200
201     def main(self):
202         """Main function.
203         """
204         test_path = os.path.join(REPO_PATH, "../samples/vnf_samples/nsut/")
205         os.chdir(os.path.join(REPO_PATH, "../"))
206         args = self.parse_arguments()
207
208         # if required, handle list-* operations
209         self.handle_list_options(args, test_path)
210
211         # check for input params
212         self.terminate_if_less_options(args)
213
214         # run test
215         self.run_test(args, test_path)
216
217 if __name__ == "__main__":
218     NS_CLI = YardstickNSCli()
219     NS_CLI.main()