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