blob: 601ccbe3c904ad3a116469ad6af1ac1c2e711b06 [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
25try:
26 import rally_runner
27except ImportError:
28 rally_runner = None
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080029
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080030
koder aka kdanilove21d7472015-02-14 19:02:04 -080031logger = logging.getLogger("io-perf-tool")
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080032logger.setLevel(logging.INFO)
koder aka kdanilove21d7472015-02-14 19:02:04 -080033ch = logging.StreamHandler()
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080034ch.setLevel(logging.INFO)
koder aka kdanilove21d7472015-02-14 19:02:04 -080035logger.addHandler(ch)
36
37log_format = '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
38formatter = logging.Formatter(log_format,
39 "%H:%M:%S")
40ch.setFormatter(formatter)
41
42
Yulia Portnova7ddfa732015-02-24 17:32:58 +020043tool_type_mapper = {
44 "iozone": IOPerfTest,
45 "fio": IOPerfTest,
46 "pgbench": PgBenchTest,
47}
48
49
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080050def run_io_test(tool,
51 script_args,
52 test_runner,
53 keep_temp_files=False):
54
55 files_dir = os.path.dirname(io_scenario.__file__)
56
57 path = 'iozone' if 'iozone' == tool else 'fio'
58 src_testtool_path = os.path.join(files_dir, path)
59
Yulia Portnova7ddfa732015-02-24 17:32:58 +020060 obj_cls = tool_type_mapper[tool]
61 obj = obj_cls(script_args,
62 src_testtool_path,
63 None,
64 keep_temp_files)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080065
66 return test_runner(obj)
67
68
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080069class FileWrapper(object):
70 def __init__(self, fd, conn):
71 self.fd = fd
72 self.channel_wr = weakref.ref(conn)
73
74 def read(self):
75 return self.fd.read()
76
77 @property
78 def channel(self):
79 return self.channel_wr()
80
81
82class LocalConnection(object):
83 def __init__(self):
84 self.proc = None
85
86 def exec_command(self, cmd):
87 PIPE = subprocess.PIPE
88 self.proc = subprocess.Popen(cmd,
89 shell=True,
90 stdout=PIPE,
91 stderr=PIPE,
92 stdin=PIPE)
93 res = (self.proc.stdin,
94 FileWrapper(self.proc.stdout, self),
95 self.proc.stderr)
koder aka kdanilov4ec0f712015-02-19 19:19:27 -080096 return res
97
98 def recv_exit_status(self):
99 return self.proc.wait()
100
101 def open_sftp(self):
102 return self
103
104 def close(self):
105 pass
106
107 def put(self, localfile, remfile):
108 return shutil.copy(localfile, remfile)
109
110 def mkdir(self, remotepath, mode):
111 os.mkdir(remotepath)
112 os.chmod(remotepath, mode)
113
114 def chmod(self, remotepath, mode):
115 os.chmod(remotepath, mode)
116
117 def copytree(self, src, dst):
118 shutil.copytree(src, dst)
119
120
121def get_local_runner(clear_tmp_files=True):
122 def closure(obj):
123 res = []
124 obj.set_result_cb(res.append)
125 test_iter = run_test_iter(obj,
126 LocalConnection())
127 next(test_iter)
128
129 with log_error("!Run test"):
130 next(test_iter)
131 return res
132
133 return closure
134
135
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800136def parse_args(argv):
137 parser = argparse.ArgumentParser(
138 description="Run disk io performance test")
139
140 parser.add_argument("tool_type", help="test tool type",
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200141 choices=['iozone', 'fio', 'pgbench'])
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800142
143 parser.add_argument("-l", dest='extra_logs',
144 action='store_true', default=False,
145 help="print some extra log info")
146
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200147 parser.add_argument("-o", "--test-opts", dest='opts',
148 help="cmd line options for test")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800149
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200150 parser.add_argument("-f", "--test-opts-file", dest='opts_file',
koder aka kdanilov3f356262015-02-13 08:06:14 -0800151 type=argparse.FileType('r'), default=None,
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200152 help="file with cmd line options for test")
153 #
154 # parser.add_argument("-t", "--test-directory", help="directory with test",
155 # dest="test_directory", required=True)
koder aka kdanilov3f356262015-02-13 08:06:14 -0800156
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200157 parser.add_argument("-t", "--test", help="test to run",
158 dest="test_directory", required=True,
159 choices=['io', 'pgbench', 'two_scripts'])
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800160
161 parser.add_argument("--max-preparation-time", default=300,
162 type=int, dest="max_preparation_time")
163
gstepanov8053b012015-02-16 17:25:27 +0200164 parser.add_argument("-b", "--build-info", default=None,
165 dest="build_name")
166
167 parser.add_argument("-d", "--data-server-url", default=None,
168 dest="data_server_url")
169
170 parser.add_argument("-n", "--lab-name", default=None,
171 dest="lab_name")
172
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800173 parser.add_argument("--create-vms-opts", default=None,
174 help="Creating vm's before run ssh runner",
175 dest="create_vms_opts")
176
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800177 parser.add_argument("-k", "--keep", default=False,
178 help="keep temporary files",
179 dest="keep_temp_files", action='store_true')
180
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800181 choices = ["local", "ssh"]
182
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800183 if rally_runner is not None:
184 choices.append("rally")
185
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800186 parser.add_argument("--runner", required=True,
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800187 choices=choices, help="runner type")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800188
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800189 parser.add_argument("--runner-extra-opts", default=None,
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800190 dest="runner_opts", help="runner extra options")
191
192 return parser.parse_args(argv)
193
194
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200195def get_opts(opts_file, test_opts):
196 if opts_file is not None and test_opts is not None:
197 print "Options --opts-file and --opts can't be " + \
koder aka kdanilov3f356262015-02-13 08:06:14 -0800198 "provided same time"
199 exit(1)
200
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200201 if opts_file is None and test_opts is None:
202 print "Either --opts-file or --opts should " + \
koder aka kdanilov3f356262015-02-13 08:06:14 -0800203 "be provided"
204 exit(1)
205
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200206 if opts_file is not None:
207 opts = []
koder aka kdanilov3f356262015-02-13 08:06:14 -0800208
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200209 opt_lines = opts_file.readlines()
koder aka kdanilov3f356262015-02-13 08:06:14 -0800210 opt_lines = [i for i in opt_lines if i != "" and not i.startswith("#")]
211
212 for opt_line in opt_lines:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800213 if opt_line.strip() != "":
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200214 opts.append([opt.strip()
215 for opt in opt_line.strip().split(" ")
216 if opt.strip() != ""])
koder aka kdanilov3f356262015-02-13 08:06:14 -0800217 else:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200218 opts = [[opt.strip()
219 for opt in test_opts.split(" ")
220 if opt.strip() != ""]]
koder aka kdanilov3f356262015-02-13 08:06:14 -0800221
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200222 if len(opts) == 0:
223 print "Can't found parameters for tests. Check" + \
224 "--opts-file or --opts options"
koder aka kdanilov3f356262015-02-13 08:06:14 -0800225 exit(1)
226
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200227 return opts
koder aka kdanilov3f356262015-02-13 08:06:14 -0800228
229
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200230def format_result(res, formatter):
koder aka kdanilove21d7472015-02-14 19:02:04 -0800231 data = "\n{0}\n".format("=" * 80)
232 data += pprint.pformat(res) + "\n"
233 data += "{0}\n".format("=" * 80)
koder aka kdanilovfe056622015-02-19 08:46:15 -0800234 templ = "{0}\n\n====> {1}\n\n{2}\n\n"
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200235 return templ.format(data, formatter(res), "=" * 80)
koder aka kdanilove21d7472015-02-14 19:02:04 -0800236
237
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800238@contextlib.contextmanager
239def start_test_vms(opts):
240 create_vms_opts = {}
241 for opt in opts.split(","):
242 name, val = opt.split("=", 1)
243 create_vms_opts[name] = val
244
245 user = create_vms_opts.pop("user")
246 key_file = create_vms_opts.pop("key_file")
247 aff_group = create_vms_opts.pop("aff_group", None)
248 raw_count = create_vms_opts.pop("count", "x1")
249
250 logger.debug("Connection to nova")
251 nova = nova_connect()
252
253 if raw_count.startswith("x"):
254 logger.debug("Getting amount of compute services")
255 count = len(nova.services.list(binary="nova-compute"))
256 count *= int(raw_count[1:])
257 else:
258 count = int(raw_count)
259
260 if aff_group is not None:
261 scheduler_hints = {'group': aff_group}
262 else:
263 scheduler_hints = None
264
265 create_vms_opts['scheduler_hints'] = scheduler_hints
266
267 logger.debug("Will start {0} vms".format(count))
268
269 try:
270 ips = [i[0] for i in create_vms_mt(nova, count, **create_vms_opts)]
271
272 uris = ["{0}@{1}::{2}".format(user, ip, key_file) for ip in ips]
273
274 yield uris
275 except:
276 traceback.print_exc()
277 finally:
278 logger.debug("Clearing")
279 clear_all(nova)
280
281
koder aka kdanilov3f356262015-02-13 08:06:14 -0800282def main(argv):
283 opts = parse_args(argv)
284
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800285 if opts.extra_logs:
286 logger.setLevel(logging.DEBUG)
287 ch.setLevel(logging.DEBUG)
koder aka kdanilov3f356262015-02-13 08:06:14 -0800288
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200289 test_opts = get_opts(opts.opts_file, opts.opts)
koder aka kdanilov3f356262015-02-13 08:06:14 -0800290
291 if opts.runner == "rally":
koder aka kdanilove21d7472015-02-14 19:02:04 -0800292 logger.debug("Use rally runner")
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200293 for script_args in test_opts:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800294
295 cmd_line = " ".join(script_args)
296 logger.debug("Run test with {0!r} params".format(cmd_line))
297
koder aka kdanilov3f356262015-02-13 08:06:14 -0800298 runner = rally_runner.get_rally_runner(
299 files_dir=os.path.dirname(io_scenario.__file__),
300 rally_extra_opts=opts.runner_opts.split(" "),
301 max_preparation_time=opts.max_preparation_time,
302 keep_temp_files=opts.keep_temp_files)
303
304 res = run_io_test(opts.tool_type,
305 script_args,
306 runner,
307 opts.keep_temp_files)
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200308 logger.debug(format_result(res, get_formatter(opts.tool_type)))
koder aka kdanilov3f356262015-02-13 08:06:14 -0800309
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800310 elif opts.runner == "local":
311 logger.debug("Run on local computer")
312 try:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200313 for script_args in test_opts:
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800314 cmd_line = " ".join(script_args)
315 logger.debug("Run test with {0!r} params".format(cmd_line))
316 runner = get_local_runner(opts.keep_temp_files)
317 res = run_io_test(opts.tool_type,
318 script_args,
319 runner,
320 opts.keep_temp_files)
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200321 logger.debug(format_result(res, get_formatter(opts.tool_type)))
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800322 except:
323 traceback.print_exc()
324 return 1
325
koder aka kdanilov3f356262015-02-13 08:06:14 -0800326 elif opts.runner == "ssh":
koder aka kdanilove21d7472015-02-14 19:02:04 -0800327 logger.debug("Use ssh runner")
koder aka kdanilov3f356262015-02-13 08:06:14 -0800328
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800329 uris = []
koder aka kdanilov3f356262015-02-13 08:06:14 -0800330
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800331 if opts.create_vms_opts is not None:
332 vm_context = start_test_vms(opts.create_vms_opts)
333 uris += vm_context.__enter__()
koder aka kdanilov3f356262015-02-13 08:06:14 -0800334 else:
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800335 vm_context = None
koder aka kdanilov3f356262015-02-13 08:06:14 -0800336
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800337 if opts.runner_opts is not None:
338 uris += opts.runner_opts.split(";")
koder aka kdanilov3f356262015-02-13 08:06:14 -0800339
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800340 if len(uris) == 0:
341 logger.critical("You need to provide at least" +
342 " vm spawn params or ssh params")
343 return 1
koder aka kdanilove21d7472015-02-14 19:02:04 -0800344
koder aka kdanilov3f356262015-02-13 08:06:14 -0800345 try:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200346 for script_args in test_opts:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800347 cmd_line = " ".join(script_args)
348 logger.debug("Run test with {0!r} params".format(cmd_line))
349 latest_start_time = opts.max_preparation_time + time.time()
koder aka kdanilov3f356262015-02-13 08:06:14 -0800350 runner = ssh_runner.get_ssh_runner(uris,
351 latest_start_time,
352 opts.keep_temp_files)
353 res = run_io_test(opts.tool_type,
354 script_args,
355 runner,
356 opts.keep_temp_files)
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200357 logger.debug(format_result(res, get_formatter(opts.tool_type)))
koder aka kdanilov3f356262015-02-13 08:06:14 -0800358
koder aka kdanilov3f356262015-02-13 08:06:14 -0800359 except:
360 traceback.print_exc()
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800361 return 1
koder aka kdanilov3f356262015-02-13 08:06:14 -0800362 finally:
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800363 if vm_context is not None:
364 vm_context.__exit__()
365 logger.debug("Clearing")
koder aka kdanilov3f356262015-02-13 08:06:14 -0800366
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800367 if opts.data_server_url:
Yulia Portnova7ddfa732015-02-24 17:32:58 +0200368 result = json.loads(get_formatter(opts.tool_type)(res))
koder aka kdanilov4ec0f712015-02-19 19:19:27 -0800369 result['name'] = opts.build_name
370 add_test(opts.build_name, result, opts.data_server_url)
371
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800372 return 0
373
374
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800375if __name__ == '__main__':
376 exit(main(sys.argv[1:]))