3 ##############################################################################
4 # Copyright (c) 2015 Ericsson AB and others.
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Apache License, Version 2.0
8 # which accompanies this distribution, and is available at
9 # http://www.apache.org/licenses/LICENSE-2.0
10 ##############################################################################
12 """ yardstick - command line tool for managing benchmarks
15 $ yardstick samples/ping-task.yaml
17 Servers are the same as VMs (Nova call them servers in the API)
19 Many tests use a client/server architecture. A test client is configured
20 to use a specific test server e.g. using an IP address. This is true for
21 example iperf. In some cases the test server is included in the kernel
22 (ping, pktgen) and no additional software is needed on the server. In other
23 cases (iperf) a server process needs to be installed and started
25 One server is required to host the test client program (such as ping or
26 iperf). In the task file this server is called host.
28 A server can be the _target_ of a test client (think ping destination
29 argument). A target server is optional but needed in most test scenarios.
30 In the task file this server is called target. This is probably the same
31 as DUT in existing terminology.
34 https://www.ietf.org/rfc/rfc1242.txt (throughput/latency)
35 https://www.ietf.org/rfc/rfc2285.txt (DUT/SUT)
48 from yardstick.benchmark.context.model import Context
49 from yardstick.benchmark.runners import base as base_runner
50 from yardstick.cmdparser import CmdParser
53 class TaskParser(object):
54 '''Parser for task config files in yaml format'''
55 def __init__(self, path):
59 '''parses the task file and return an context and scenario instances'''
60 print "Parsing task config:", self.path
62 with open(self.path) as stream:
63 cfg = yaml.load(stream)
64 except IOError as ioerror:
67 if cfg["schema"] != "yardstick:task:0.1":
68 sys.exit("error: file %s has unknown schema %s" % (self.path,
71 # TODO: support one or many contexts? Many would simpler and precise
73 context_cfgs = [cfg["context"]]
75 context_cfgs = cfg["contexts"]
77 for cfg_attrs in context_cfgs:
79 context.init(cfg_attrs)
81 run_in_parallel = cfg.get("run_in_parallel", False)
83 # TODO we need something better here, a class that represent the file
84 return cfg["scenarios"], run_in_parallel
88 '''handler for process termination'''
89 base_runner.Runner.terminate_all()
91 if len(Context.list) > 0:
92 print "Undeploying all contexts"
93 for context in Context.list:
98 '''check if string addr is an IP address'''
100 ipaddress.ip_address(addr)
106 def run_one_scenario(scenario_cfg, output_file):
107 '''run one scenario using context'''
108 key_filename = pkg_resources.resource_filename(
109 'yardstick.resources', 'files/yardstick_key')
111 host = Context.get_server(scenario_cfg["host"])
113 runner_cfg = scenario_cfg["runner"]
114 runner_cfg['host'] = host.public_ip
115 runner_cfg['user'] = host.context.user
116 runner_cfg['key_filename'] = key_filename
117 runner_cfg['output_filename'] = output_file
119 if "target" in scenario_cfg:
120 if is_ip_addr(scenario_cfg["target"]):
121 scenario_cfg["ipaddr"] = scenario_cfg["target"]
123 target = Context.get_server(scenario_cfg["target"])
125 # get public IP for target server, some scenarios require it
127 runner_cfg['target'] = target.public_ip
129 # TODO scenario_cfg["ipaddr"] is bad naming
130 if host.context != target.context:
131 # target is in another context, get its public IP
132 scenario_cfg["ipaddr"] = target.public_ip
134 # target is in the same context, get its private IP
135 scenario_cfg["ipaddr"] = target.private_ip
137 runner = base_runner.Runner.get(runner_cfg)
139 print "Starting runner of type '%s'" % runner_cfg["type"]
140 runner.run(scenario_cfg["type"], scenario_cfg)
145 def runner_join(runner):
146 '''join (wait for) a runner, exit process at runner failure'''
147 status = runner.join()
148 base_runner.Runner.release(runner)
150 sys.exit("Runner failed")
156 atexit.register(atexit_handler)
158 prog_args = CmdParser().parse_args()
160 parser = TaskParser(prog_args.taskfile[0])
161 scenarios, run_in_parallel = parser.parse()
163 if prog_args.parse_only:
166 for context in Context.list:
171 for scenario in scenarios:
172 runner = run_one_scenario(scenario, prog_args.output_file)
173 runners.append(runner)
175 # Wait for runners to finish
176 for runner in runners:
178 print "Runner ended, output in", prog_args.output_file
181 for scenario in scenarios:
182 runner = run_one_scenario(scenario, prog_args.output_file)
184 print "Runner ended, output in", prog_args.output_file
186 if prog_args.keep_deploy:
187 # keep deployment, forget about stack (hide it for exit handler)
190 for context in Context.list:
193 print "Done, exiting"
195 if __name__ == '__main__':