blob: f1800fd5ccbb349cb44145f6cbf6b7a2799604fd [file] [log] [blame]
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08001import os
2import sys
3import json
4import time
koder aka kdanilov4ec0f712015-02-19 19:19:27 -08005import shutil
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08006import pprint
koder aka kdanilov4ec0f712015-02-19 19:19:27 -08007import weakref
koder aka kdanilove21d7472015-02-14 19:02:04 -08008import logging
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08009import os.path
10import argparse
koder aka kdanilov3f356262015-02-13 08:06:14 -080011import traceback
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080012import subprocess
13import contextlib
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080014
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080015
16import ssh_runner
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080017import io_scenario
18from utils import log_error
19from rest_api import add_test
Yulia Portnova7ddfa732015-02-24 17:32:58 +020020from itest import IOPerfTest, run_test_iter, PgBenchTest
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080021from starts_vms import nova_connect, create_vms_mt, clear_all
Yulia Portnova7ddfa732015-02-24 17:32:58 +020022from formatters import get_formatter
23
koder aka kdanilov7dec9df2015-02-15 21:35:19 -080024
koder aka kdanilove21d7472015-02-14 19:02:04 -080025logger = logging.getLogger("io-perf-tool")
yportnovaa47b33e2015-03-05 20:20:31 +020026logger.setLevel(logging.DEBUG)
koder aka kdanilove21d7472015-02-14 19:02:04 -080027ch = logging.StreamHandler()
yportnovaa47b33e2015-03-05 20:20:31 +020028ch.setLevel(logging.DEBUG)
koder aka kdanilove21d7472015-02-14 19:02:04 -080029logger.addHandler(ch)
30
31log_format = '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
32formatter = logging.Formatter(log_format,
33 "%H:%M:%S")
34ch.setFormatter(formatter)
35
36
Yulia Portnova7ddfa732015-02-24 17:32:58 +020037tool_type_mapper = {
38 "iozone": IOPerfTest,
39 "fio": IOPerfTest,
40 "pgbench": PgBenchTest,
41}
42
43
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080044def run_io_test(tool,
45 script_args,
46 test_runner,
47 keep_temp_files=False):
48
49 files_dir = os.path.dirname(io_scenario.__file__)
50
51 path = 'iozone' if 'iozone' == tool else 'fio'
52 src_testtool_path = os.path.join(files_dir, path)
53
Yulia Portnova7ddfa732015-02-24 17:32:58 +020054 obj_cls = tool_type_mapper[tool]
55 obj = obj_cls(script_args,
56 src_testtool_path,
57 None,
58 keep_temp_files)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080059
60 return test_runner(obj)
61
62
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080063class FileWrapper(object):
64 def __init__(self, fd, conn):
65 self.fd = fd
66 self.channel_wr = weakref.ref(conn)
67
68 def read(self):
69 return self.fd.read()
70
71 @property
72 def channel(self):
73 return self.channel_wr()
74
75
76class LocalConnection(object):
77 def __init__(self):
78 self.proc = None
79
80 def exec_command(self, cmd):
81 PIPE = subprocess.PIPE
82 self.proc = subprocess.Popen(cmd,
83 shell=True,
84 stdout=PIPE,
85 stderr=PIPE,
86 stdin=PIPE)
87 res = (self.proc.stdin,
88 FileWrapper(self.proc.stdout, self),
89 self.proc.stderr)
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080090 return res
91
92 def recv_exit_status(self):
93 return self.proc.wait()
94
95 def open_sftp(self):
96 return self
97
98 def close(self):
99 pass
100
101 def put(self, localfile, remfile):
102 return shutil.copy(localfile, remfile)
103
104 def mkdir(self, remotepath, mode):
105 os.mkdir(remotepath)
106 os.chmod(remotepath, mode)
107
108 def chmod(self, remotepath, mode):
109 os.chmod(remotepath, mode)
110
111 def copytree(self, src, dst):
112 shutil.copytree(src, dst)
113
114
115def get_local_runner(clear_tmp_files=True):
116 def closure(obj):
117 res = []
118 obj.set_result_cb(res.append)
119 test_iter = run_test_iter(obj,
120 LocalConnection())
121 next(test_iter)
122
123 with log_error("!Run test"):
124 next(test_iter)
125 return res
126
127 return closure
128
129
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800130def parse_args(argv):
131 parser = argparse.ArgumentParser(
132 description="Run disk io performance test")
133
134 parser.add_argument("tool_type", help="test tool type",
yportnovaa47b33e2015-03-05 20:20:31 +0200135 choices=['iozone', 'fio', 'pgbench', 'two_scripts'])
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800136
137 parser.add_argument("-l", dest='extra_logs',
138 action='store_true', default=False,
139 help="print some extra log info")
140
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200141 parser.add_argument("-o", "--test-opts", dest='opts',
142 help="cmd line options for test")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800143
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200144 parser.add_argument("-f", "--test-opts-file", dest='opts_file',
koder aka kdanilov3f356262015-02-13 08:06:14 -0800145 type=argparse.FileType('r'), default=None,
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200146 help="file with cmd line options for test")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800147
148 parser.add_argument("--max-preparation-time", default=300,
149 type=int, dest="max_preparation_time")
150
gstepanov8053b012015-02-16 17:25:27 +0200151 parser.add_argument("-b", "--build-info", default=None,
152 dest="build_name")
153
154 parser.add_argument("-d", "--data-server-url", default=None,
155 dest="data_server_url")
156
157 parser.add_argument("-n", "--lab-name", default=None,
158 dest="lab_name")
159
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800160 parser.add_argument("--create-vms-opts", default=None,
161 help="Creating vm's before run ssh runner",
162 dest="create_vms_opts")
163
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800164 parser.add_argument("-k", "--keep", default=False,
165 help="keep temporary files",
166 dest="keep_temp_files", action='store_true')
167
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800168 choices = ["local", "ssh"]
169
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800170 parser.add_argument("--runner", required=True,
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800171 choices=choices, help="runner type")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800172
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800173 parser.add_argument("--runner-extra-opts", default=None,
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800174 dest="runner_opts", help="runner extra options")
175
176 return parser.parse_args(argv)
177
178
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200179def get_opts(opts_file, test_opts):
180 if opts_file is not None and test_opts is not None:
181 print "Options --opts-file and --opts can't be " + \
koder aka kdanilov3f356262015-02-13 08:06:14 -0800182 "provided same time"
183 exit(1)
184
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200185 if opts_file is None and test_opts is None:
186 print "Either --opts-file or --opts should " + \
koder aka kdanilov3f356262015-02-13 08:06:14 -0800187 "be provided"
188 exit(1)
189
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200190 if opts_file is not None:
191 opts = []
koder aka kdanilov3f356262015-02-13 08:06:14 -0800192
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200193 opt_lines = opts_file.readlines()
koder aka kdanilov3f356262015-02-13 08:06:14 -0800194 opt_lines = [i for i in opt_lines if i != "" and not i.startswith("#")]
195
196 for opt_line in opt_lines:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800197 if opt_line.strip() != "":
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200198 opts.append([opt.strip()
199 for opt in opt_line.strip().split(" ")
200 if opt.strip() != ""])
koder aka kdanilov3f356262015-02-13 08:06:14 -0800201 else:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200202 opts = [[opt.strip()
203 for opt in test_opts.split(" ")
204 if opt.strip() != ""]]
koder aka kdanilov3f356262015-02-13 08:06:14 -0800205
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200206 if len(opts) == 0:
207 print "Can't found parameters for tests. Check" + \
208 "--opts-file or --opts options"
koder aka kdanilov3f356262015-02-13 08:06:14 -0800209 exit(1)
210
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200211 return opts
koder aka kdanilov3f356262015-02-13 08:06:14 -0800212
213
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200214def format_result(res, formatter):
koder aka kdanilove21d7472015-02-14 19:02:04 -0800215 data = "\n{0}\n".format("=" * 80)
216 data += pprint.pformat(res) + "\n"
217 data += "{0}\n".format("=" * 80)
koder aka kdanilovfe056622015-02-19 08:46:15 -0800218 templ = "{0}\n\n====> {1}\n\n{2}\n\n"
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200219 return templ.format(data, formatter(res), "=" * 80)
koder aka kdanilove21d7472015-02-14 19:02:04 -0800220
221
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800222@contextlib.contextmanager
223def start_test_vms(opts):
224 create_vms_opts = {}
225 for opt in opts.split(","):
226 name, val = opt.split("=", 1)
227 create_vms_opts[name] = val
228
229 user = create_vms_opts.pop("user")
230 key_file = create_vms_opts.pop("key_file")
231 aff_group = create_vms_opts.pop("aff_group", None)
232 raw_count = create_vms_opts.pop("count", "x1")
233
234 logger.debug("Connection to nova")
235 nova = nova_connect()
236
237 if raw_count.startswith("x"):
238 logger.debug("Getting amount of compute services")
239 count = len(nova.services.list(binary="nova-compute"))
240 count *= int(raw_count[1:])
241 else:
242 count = int(raw_count)
243
244 if aff_group is not None:
245 scheduler_hints = {'group': aff_group}
246 else:
247 scheduler_hints = None
248
249 create_vms_opts['scheduler_hints'] = scheduler_hints
250
251 logger.debug("Will start {0} vms".format(count))
252
253 try:
254 ips = [i[0] for i in create_vms_mt(nova, count, **create_vms_opts)]
255
256 uris = ["{0}@{1}::{2}".format(user, ip, key_file) for ip in ips]
257
258 yield uris
259 except:
260 traceback.print_exc()
261 finally:
262 logger.debug("Clearing")
263 clear_all(nova)
264
265
koder aka kdanilov3f356262015-02-13 08:06:14 -0800266def main(argv):
267 opts = parse_args(argv)
268
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800269 if opts.extra_logs:
270 logger.setLevel(logging.DEBUG)
271 ch.setLevel(logging.DEBUG)
koder aka kdanilov3f356262015-02-13 08:06:14 -0800272
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200273 test_opts = get_opts(opts.opts_file, opts.opts)
koder aka kdanilov3f356262015-02-13 08:06:14 -0800274
Yulia Portnovadee7ec42015-03-11 15:42:16 +0200275 if opts.runner == "local":
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800276 logger.debug("Run on local computer")
277 try:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200278 for script_args in test_opts:
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800279 cmd_line = " ".join(script_args)
280 logger.debug("Run test with {0!r} params".format(cmd_line))
281 runner = get_local_runner(opts.keep_temp_files)
282 res = run_io_test(opts.tool_type,
283 script_args,
284 runner,
285 opts.keep_temp_files)
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200286 logger.debug(format_result(res, get_formatter(opts.tool_type)))
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800287 except:
288 traceback.print_exc()
289 return 1
290
koder aka kdanilov3f356262015-02-13 08:06:14 -0800291 elif opts.runner == "ssh":
koder aka kdanilove21d7472015-02-14 19:02:04 -0800292 logger.debug("Use ssh runner")
koder aka kdanilov3f356262015-02-13 08:06:14 -0800293
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800294 uris = []
koder aka kdanilov3f356262015-02-13 08:06:14 -0800295
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800296 if opts.create_vms_opts is not None:
297 vm_context = start_test_vms(opts.create_vms_opts)
298 uris += vm_context.__enter__()
koder aka kdanilov3f356262015-02-13 08:06:14 -0800299 else:
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800300 vm_context = None
koder aka kdanilov3f356262015-02-13 08:06:14 -0800301
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800302 if opts.runner_opts is not None:
303 uris += opts.runner_opts.split(";")
koder aka kdanilov3f356262015-02-13 08:06:14 -0800304
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800305 if len(uris) == 0:
306 logger.critical("You need to provide at least" +
307 " vm spawn params or ssh params")
308 return 1
koder aka kdanilove21d7472015-02-14 19:02:04 -0800309
koder aka kdanilov3f356262015-02-13 08:06:14 -0800310 try:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200311 for script_args in test_opts:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800312 cmd_line = " ".join(script_args)
313 logger.debug("Run test with {0!r} params".format(cmd_line))
314 latest_start_time = opts.max_preparation_time + time.time()
koder aka kdanilov3f356262015-02-13 08:06:14 -0800315 runner = ssh_runner.get_ssh_runner(uris,
316 latest_start_time,
317 opts.keep_temp_files)
318 res = run_io_test(opts.tool_type,
319 script_args,
320 runner,
321 opts.keep_temp_files)
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200322 logger.debug(format_result(res, get_formatter(opts.tool_type)))
koder aka kdanilov3f356262015-02-13 08:06:14 -0800323
koder aka kdanilov3f356262015-02-13 08:06:14 -0800324 except:
325 traceback.print_exc()
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800326 return 1
koder aka kdanilov3f356262015-02-13 08:06:14 -0800327 finally:
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800328 if vm_context is not None:
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800329 vm_context.__exit__(None, None, None)
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800330 logger.debug("Clearing")
koder aka kdanilov3f356262015-02-13 08:06:14 -0800331
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800332 if opts.data_server_url:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200333 result = json.loads(get_formatter(opts.tool_type)(res))
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800334 result['name'] = opts.build_name
335 add_test(opts.build_name, result, opts.data_server_url)
336
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800337 return 0
338
339
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800340if __name__ == '__main__':
341 exit(main(sys.argv[1:]))