2 # Copyright (c) 2016-2017 Intel Corporation
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 """NSBPERF main script.
20 from __future__ import absolute_import
21 from __future__ import print_function
27 from oslo_serialization import jsonutils
29 from six.moves import input
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)
37 if not PYTHONPATH or not VIRTUAL_ENV:
38 print("Please setup env PYTHONPATH & VIRTUAL_ENV environment varaible.")
42 def sigint_handler(*args, **kwargs):
43 """ Capture ctrl+c and exit cli """
44 subprocess.call(["pkill", "-9", "yardstick"])
48 class YardstickNSCli(object):
49 """ This class handles yardstick network serivce testing """
52 super(YardstickNSCli, self).__init__()
55 def validate_input(cls, choice, choice_len):
56 """ Validate user inputs """
61 if not 1 <= choice <= choice_len:
62 print("\nInvalid wrong choice...")
63 input("Press Enter to continue...")
65 subprocess.call(['clear'])
69 def parse_arguments(cls):
71 Parse command line arguments.
74 argparse.ArgumentParser(
76 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
77 parser.add_argument('--version', action='version',
78 version='%(prog)s 0.1')
79 parser.add_argument('--list', '--list-tests', action='store_true',
80 help='list all tests and exit')
81 parser.add_argument('--list-vnfs', action='store_true',
82 help='list all system vnfs and exit')
84 group = parser.add_argument_group('test selection options')
85 group.add_argument('--vnf', help='vnf to use')
86 group.add_argument('--test', help='test in use')
88 args = vars(parser.parse_args())
93 def generate_kpi_results(cls, tkey, tgen):
94 """ Generate report for vnf & traffic generator kpis """
96 print("\n%s stats" % tkey)
97 print("----------------------------")
98 for key, value in tgen.items():
99 if key != "collect_stats":
100 print(json.dumps({key: value}, indent=2))
103 def generate_nfvi_results(cls, nfvi):
104 """ Generate report for vnf & traffic generator kpis """
106 nfvi_kpi = {k: v for k, v in nfvi.items() if k == 'collect_stats'}
108 print("\nNFVi stats")
109 print("----------------------------")
110 for key, value in nfvi_kpi.items():
111 print(json.dumps({key: value}, indent=2))
113 def generate_final_report(self, test_case):
114 """ Function will check if partial test results are available
115 and generates final report in rst format.
118 report_caption = '{}\n{} ({})\n{}\n\n'.format(
119 '================================================================',
120 'Performance report for',
121 os.path.splitext(test_case)[0].upper(),
122 '================================================================')
123 print(report_caption)
124 if os.path.isfile("/tmp/yardstick.out"):
126 with open("/tmp/yardstick.out") as infile:
127 lines = jsonutils.load(infile)
130 lines = lines['result']
131 tc_res = lines.pop(len(lines) - 1)
132 for key, value in tc_res["benchmark"]["data"].items():
133 self.generate_kpi_results(key, value)
134 self.generate_nfvi_results(value)
137 def handle_list_options(cls, args, test_path):
138 """ Process --list cli arguments if needed
140 :param args: A dictionary with all CLI arguments
142 if args['list_vnfs']:
143 vnfs = os.listdir(test_path)
145 print("================")
146 for index, vnf in enumerate(vnfs, 1):
147 print((' %-2s %s' % ('%s:' % str(index), vnf)))
151 vnfs = os.listdir(test_path)
153 print("Available Tests:")
154 print("*****************")
156 testcases = os.listdir(test_path + vnf)
157 print(("VNF :(%s)" % vnf))
158 print("================")
159 for testcase in [tc for tc in testcases if "tc" in tc]:
160 print('%s' % testcase)
165 def terminate_if_less_options(cls, args):
166 """ terminate cli if cmdline options is invalid """
167 if not (args["vnf"] and args["test"]):
168 print("CLI needs option, make sure to pass vnf, test")
169 print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
172 def run_test(self, args, test_path):
173 """ run requested test """
175 vnf = args.get("vnf", "")
176 test = args.get("test", "")
178 vnf_dir = test_path + os.sep + vnf
179 if not os.path.exists(vnf_dir):
180 raise ValueError("'%s', vnf not supported." % vnf)
182 testcases = [tc for tc in os.listdir(vnf_dir) if "tc" in tc]
183 subtest = set([test]).issubset(testcases)
185 raise ValueError("'%s', testcase not supported." % test)
188 # fixme: Use REST APIs to initiate testcases
189 subprocess.check_output(["yardstick", "--debug",
190 "task", "start", test])
191 self.generate_final_report(test)
192 except (IOError, ValueError):
193 print("Value/I/O error...")
194 except BaseException:
195 print("Test failed. Please verify test inputs & re-run the test..")
196 print("eg: NSBperf.py --vnf <vnf untertest> --test <test yaml>")
201 test_path = os.path.join(REPO_PATH, "../samples/vnf_samples/nsut/")
202 os.chdir(os.path.join(REPO_PATH, "../"))
203 args = self.parse_arguments()
205 # if required, handle list-* operations
206 self.handle_list_options(args, test_path)
208 # check for input params
209 self.terminate_if_less_options(args)
212 self.run_test(args, test_path)
214 if __name__ == "__main__":
215 signal.signal(signal.SIGINT, sigint_handler)
216 NS_CLI = YardstickNSCli()