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.")
43 """ Capture ctrl+c and exit cli """
44 subprocess.call(["pkill", "-9", "yardstick"])
47 signal.signal(signal.SIGINT, handler)
50 class YardstickNSCli(object):
51 """ This class handles yardstick network serivce testing """
54 super(YardstickNSCli, self).__init__()
57 def validate_input(cls, choice, choice_len):
58 """ Validate user inputs """
63 if not 1 <= choice <= choice_len:
64 print("\nInvalid wrong choice...")
65 input("Press Enter to continue...")
67 subprocess.call(['clear'])
71 def parse_arguments(cls):
73 Parse command line arguments.
76 argparse.ArgumentParser(
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')
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')
90 args = vars(parser.parse_args())
95 def generate_kpi_results(cls, tkey, tgen):
96 """ Generate report for vnf & traffic generator kpis """
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))
105 def generate_nfvi_results(cls, nfvi):
106 """ Generate report for vnf & traffic generator kpis """
108 nfvi_kpi = {k: v for k, v in nfvi.items() if k == 'collect_stats'}
110 print("\nNFVi stats")
111 print("----------------------------")
112 for key, value in nfvi_kpi.items():
113 print(json.dumps({key: value}, indent=2))
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.
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"):
128 with open("/tmp/yardstick.out") as infile:
129 lines = jsonutils.load(infile)
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)
140 def handle_list_options(cls, args, test_path):
141 """ Process --list cli arguments if needed
143 :param args: A dictionary with all CLI arguments
145 if args['list_vnfs']:
146 vnfs = os.listdir(test_path)
148 print("================")
149 for index, vnf in enumerate(vnfs, 1):
150 print((' %-2s %s' % ('%s:' % str(index), vnf)))
154 vnfs = os.listdir(test_path)
156 print("Available Tests:")
157 print("*****************")
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)
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>")
175 def run_test(self, args, test_path):
176 """ run requested test """
178 vnf = args.get("vnf", "")
179 test = args.get("test", "")
181 vnf_dir = test_path + os.sep + vnf
182 if not os.path.exists(vnf_dir):
183 raise ValueError("'%s', vnf not supported." % vnf)
185 testcases = [tc for tc in os.listdir(vnf_dir) if "tc" in tc]
186 subtest = set([test]).issubset(testcases)
188 raise ValueError("'%s', testcase not supported." % test)
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>")
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()
208 # if required, handle list-* operations
209 self.handle_list_options(args, test_path)
211 # check for input params
212 self.terminate_if_less_options(args)
215 self.run_test(args, test_path)
217 if __name__ == "__main__":
218 NS_CLI = YardstickNSCli()