Merge "heat: convert open to context manager"
[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
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         report_caption = '{}\n{} ({})\n{}\n\n'.format(
121             '================================================================',
122             'Performance report for',
123             os.path.splitext(test_case)[0].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 = infile.readlines()
130
131             if lines:
132                 tc_res = json.loads(lines.pop(len(lines) - 1))
133                 for key, value in tc_res["benchmark"]["data"].items():
134                     self.generate_kpi_results(key, value)
135                     self.generate_nfvi_results(value)
136
137     @classmethod
138     def handle_list_options(cls, args, test_path):
139         """ Process --list cli arguments if needed
140
141         :param args: A dictionary with all CLI arguments
142         """
143         if args['list_vnfs']:
144             vnfs = os.listdir(test_path)
145             print("VNF :")
146             print("================")
147             for index, vnf in enumerate(vnfs, 1):
148                 print((' %-2s %s' % ('%s:' % str(index), vnf)))
149             raise SystemExit(0)
150
151         if args['list']:
152             vnfs = os.listdir(test_path)
153
154             print("Available Tests:")
155             print("*****************")
156             for vnf in vnfs:
157                 testcases = os.listdir(test_path + vnf)
158                 print(("VNF :(%s)" % vnf))
159                 print("================")
160                 for testcase in [tc for tc in testcases if "tc" in tc]:
161                     print('%s' % testcase)
162                 print(os.linesep)
163             raise SystemExit(0)
164
165     @classmethod
166     def terminate_if_less_options(cls, args):
167         """ terminate cli if cmdline options is invalid """
168         if not (args["vnf"] and args["test"]):
169             print("CLI needs option, make sure to pass vnf, test")
170             print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
171             raise SystemExit(1)
172
173     def run_test(self, args, test_path):
174         """ run requested test """
175         try:
176             vnf = args.get("vnf", "")
177             test = args.get("test", "")
178
179             vnf_dir = test_path + os.sep + vnf
180             if not os.path.exists(vnf_dir):
181                 raise ValueError("'%s', vnf not supported." % vnf)
182
183             testcases = [tc for tc in os.listdir(vnf_dir) if "tc" in tc]
184             subtest = set([test]).issubset(testcases)
185             if not subtest:
186                 raise ValueError("'%s', testcase not supported." % test)
187
188             os.chdir(vnf_dir)
189             # fixme: Use REST APIs to initiate testcases
190             subprocess.check_output(["yardstick", "--debug",
191                                      "task", "start", test])
192             self.generate_final_report(test)
193         except (IOError, ValueError):
194             print("Value/I/O error...")
195         except BaseException:
196             print("Test failed. Please verify test inputs & re-run the test..")
197             print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
198
199     def main(self):
200         """Main function.
201         """
202         test_path = os.path.join(REPO_PATH, "../samples/vnf_samples/nsut/")
203         os.chdir(os.path.join(REPO_PATH, "../"))
204         args = self.parse_arguments()
205
206         # if required, handle list-* operations
207         self.handle_list_options(args, test_path)
208
209         # check for input params
210         self.terminate_if_less_options(args)
211
212         # run test
213         self.run_test(args, test_path)
214
215 if __name__ == "__main__":
216     NS_CLI = YardstickNSCli()
217     NS_CLI.main()