blob: daebd1a1a9846bdc2e38189258077d6fbb7cee62 [file] [log] [blame]
koder aka kdanilov4643fd62015-02-10 16:20:13 -08001import abc
2import json
koder aka kdanilov4643fd62015-02-10 16:20:13 -08003import os.path
koder aka kdanilove21d7472015-02-14 19:02:04 -08004import logging
koder aka kdanilov2c473092015-03-29 17:12:13 +03005from StringIO import StringIO
6from ConfigParser import RawConfigParser
koder aka kdanilove21d7472015-02-14 19:02:04 -08007
koder aka kdanilov2c473092015-03-29 17:12:13 +03008from tests import io
koder aka kdanilov3a6633e2015-03-26 18:20:00 +02009from ssh_utils import copy_paths
koder aka kdanilov2c473092015-03-29 17:12:13 +030010from utils import run_over_ssh, ssize_to_b
koder aka kdanilov4643fd62015-02-10 16:20:13 -080011
12
koder aka kdanilove21d7472015-02-14 19:02:04 -080013logger = logging.getLogger("io-perf-tool")
14
15
koder aka kdanilov4643fd62015-02-10 16:20:13 -080016class IPerfTest(object):
17 def __init__(self, on_result_cb):
18 self.on_result_cb = on_result_cb
19
koder aka kdanilov4643fd62015-02-10 16:20:13 -080020 def pre_run(self, conn):
21 pass
22
23 @abc.abstractmethod
koder aka kdanilov2c473092015-03-29 17:12:13 +030024 def run(self, conn, barrier):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080025 pass
26
27
Yulia Portnova7ddfa732015-02-24 17:32:58 +020028class TwoScriptTest(IPerfTest):
29 def __init__(self, opts, testtool, on_result_cb, keep_tmp_files):
30 super(TwoScriptTest, self).__init__(on_result_cb)
31 self.opts = opts
32 self.pre_run_script = None
33 self.run_script = None
34 self.tmp_dir = "/tmp/"
35 self.set_run_script()
36 self.set_pre_run_script()
37
38 def set_run_script(self):
39 self.pre_run_script = self.opts.pre_run_script
40
41 def set_pre_run_script(self):
42 self.run_script = self.opts.run_script
43
44 def get_remote_for_script(self, script):
45 return os.path.join(self.tmp_dir, script.rpartition('/')[2])
46
47 def copy_script(self, conn, src):
48 remote_path = self.get_remote_for_script(src)
49 copy_paths(conn, {src: remote_path})
50 return remote_path
51
52 def pre_run(self, conn):
53 remote_script = self.copy_script(conn, self.pre_run_script)
54 cmd = remote_script
koder aka kdanilov2c473092015-03-29 17:12:13 +030055 code, out_err = run_over_ssh(conn, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020056 if code != 0:
koder aka kdanilov2c473092015-03-29 17:12:13 +030057 raise Exception("Pre run failed. %s" % out_err)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020058
koder aka kdanilov2c473092015-03-29 17:12:13 +030059 def run(self, conn, barrier):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020060 remote_script = self.copy_script(conn, self.run_script)
Yulia Portnova3f65e7c2015-02-25 17:19:35 +020061 cmd = remote_script + ' ' + ' '.join(self.opts)
koder aka kdanilov2c473092015-03-29 17:12:13 +030062 code, out_err = run_over_ssh(conn, cmd)
63 self.on_result(code, out_err, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020064
65 def parse_results(self, out):
66 for line in out.split("\n"):
67 key, separator, value = line.partition(":")
68 if key and value:
69 self.on_result_cb((key, float(value)))
70
koder aka kdanilov2c473092015-03-29 17:12:13 +030071 def on_result(self, code, out_err, cmd):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020072 if 0 == code:
73 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +030074 self.parse_results(out_err)
75 except Exception as exc:
Yulia Portnova7ddfa732015-02-24 17:32:58 +020076 msg_templ = "Error during postprocessing results: {0!r}"
koder aka kdanilov2c473092015-03-29 17:12:13 +030077 raise RuntimeError(msg_templ.format(exc.message))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020078 else:
79 templ = "Command {0!r} failed with code {1}. Error output is:\n{2}"
koder aka kdanilov2c473092015-03-29 17:12:13 +030080 logger.error(templ.format(cmd, code, out_err))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020081
82
83class PgBenchTest(TwoScriptTest):
84
85 def set_run_script(self):
86 self.pre_run_script = "hl_tests/postgres/prepare.sh"
87
88 def set_pre_run_script(self):
89 self.run_script = "hl_tests/postgres/run.sh"
90
91
koder aka kdanilov4643fd62015-02-10 16:20:13 -080092class IOPerfTest(IPerfTest):
koder aka kdanilov2c473092015-03-29 17:12:13 +030093 io_py_remote = "/tmp/io.py"
94
koder aka kdanilov4643fd62015-02-10 16:20:13 -080095 def __init__(self,
koder aka kdanilov2c473092015-03-29 17:12:13 +030096 test_options,
97 on_result_cb):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080098 IPerfTest.__init__(self, on_result_cb)
koder aka kdanilov2c473092015-03-29 17:12:13 +030099 self.options = test_options
100 self.config_fname = test_options['config_file']
101 self.tool = test_options['tool']
102 self.configs = []
koder aka kdanilov50f18642015-02-11 08:54:44 -0800103
koder aka kdanilov2c473092015-03-29 17:12:13 +0300104 cp = RawConfigParser()
105 cp.readfp(open(self.config_fname))
koder aka kdanilov50f18642015-02-11 08:54:44 -0800106
koder aka kdanilov2c473092015-03-29 17:12:13 +0300107 for secname in cp.sections():
108 params = dict(cp.items(secname))
109 self.configs.append((secname, params))
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800110
111 def pre_run(self, conn):
koder aka kdanilov2c473092015-03-29 17:12:13 +0300112 local_fname = io.__file__.rsplit('.')[0] + ".py"
113 self.files_to_copy = {local_fname: self.io_py_remote}
koder aka kdanilov50f18642015-02-11 08:54:44 -0800114 copy_paths(conn, self.files_to_copy)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800115
koder aka kdanilov2c473092015-03-29 17:12:13 +0300116 cmd_templ = "dd if=/dev/zero of={0} bs={1} count={2}"
117 for secname, params in self.configs:
118 sz = ssize_to_b(params['size'])
119 msz = msz = sz / (1024 ** 2)
120 if sz % (1024 ** 2) != 0:
121 msz += 1
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800122
koder aka kdanilov2c473092015-03-29 17:12:13 +0300123 cmd = cmd_templ.format(params['filename'], 1024 ** 2, msz)
124 code, out_err = run_over_ssh(conn, cmd)
125
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800126 if code != 0:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300127 raise RuntimeError("Preparation failed " + out_err)
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800128
koder aka kdanilov2c473092015-03-29 17:12:13 +0300129 def run(self, conn, barrier):
130 cmd_templ = "env python2 {0} --type {1} --json -"
131 cmd = cmd_templ.format(self.io_py_remote, self.tool)
132 try:
133 for secname, _params in self.configs:
134 params = _params.copy()
135 count = params.pop('count', 1)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800136
koder aka kdanilov2c473092015-03-29 17:12:13 +0300137 config = RawConfigParser()
138 config.add_section(secname)
139
140 for k, v in params.items():
141 config.set(secname, k, v)
142
143 cfg = StringIO()
144 config.write(cfg)
145
146 # FIX python config parser-fio incompatibility
147 # remove spaces around '='
148 new_cfg = []
149 config_data = cfg.getvalue()
150 for line in config_data.split("\n"):
151 if '=' in line:
152 name, val = line.split('=', 1)
153 name = name.strip()
154 val = val.strip()
155 line = "{0}={1}".format(name, val)
156 new_cfg.append(line)
157
158 for _ in range(count):
159 barrier.wait()
160 code, out_err = run_over_ssh(conn, cmd,
161 stdin_data="\n".join(new_cfg))
162 self.on_result(code, out_err, cmd)
163 finally:
164 barrier.exit()
165
166 def on_result(self, code, out_err, cmd):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800167 if 0 == code:
168 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300169 for line in out_err.split("\n"):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800170 if line.strip() != "":
171 self.on_result_cb(json.loads(line))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300172 except Exception as exc:
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800173 msg_templ = "Error during postprocessing results: {0!r}"
koder aka kdanilov2c473092015-03-29 17:12:13 +0300174 raise RuntimeError(msg_templ.format(exc.message))
koder aka kdanilove21d7472015-02-14 19:02:04 -0800175 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300176 templ = "Command {0!r} failed with code {1}. Output is:\n{2}"
177 logger.error(templ.format(cmd, code, out_err))