blob: e7fd3eb7b1e9dccc2e12b5b0335368838d3c7412 [file] [log] [blame]
koder aka kdanilovda45e882015-04-06 02:24:42 +03001import re
koder aka kdanilov4643fd62015-02-10 16:20:13 -08002import abc
3import json
koder aka kdanilov4643fd62015-02-10 16:20:13 -08004import os.path
koder aka kdanilove21d7472015-02-14 19:02:04 -08005import logging
koder aka kdanilov2c473092015-03-29 17:12:13 +03006from StringIO import StringIO
7from ConfigParser import RawConfigParser
koder aka kdanilove21d7472015-02-14 19:02:04 -08008
koder aka kdanilovda45e882015-04-06 02:24:42 +03009from tests import disk_test_agent
koder aka kdanilov3a6633e2015-03-26 18:20:00 +020010from ssh_utils import copy_paths
koder aka kdanilov2c473092015-03-29 17:12:13 +030011from utils import run_over_ssh, ssize_to_b
koder aka kdanilov4643fd62015-02-10 16:20:13 -080012
13
koder aka kdanilove21d7472015-02-14 19:02:04 -080014logger = logging.getLogger("io-perf-tool")
15
16
koder aka kdanilov4643fd62015-02-10 16:20:13 -080017class IPerfTest(object):
18 def __init__(self, on_result_cb):
19 self.on_result_cb = on_result_cb
20
koder aka kdanilov4643fd62015-02-10 16:20:13 -080021 def pre_run(self, conn):
22 pass
23
24 @abc.abstractmethod
koder aka kdanilov2c473092015-03-29 17:12:13 +030025 def run(self, conn, barrier):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080026 pass
27
28
Yulia Portnova7ddfa732015-02-24 17:32:58 +020029class TwoScriptTest(IPerfTest):
30 def __init__(self, opts, testtool, on_result_cb, keep_tmp_files):
31 super(TwoScriptTest, self).__init__(on_result_cb)
32 self.opts = opts
33 self.pre_run_script = None
34 self.run_script = None
35 self.tmp_dir = "/tmp/"
36 self.set_run_script()
37 self.set_pre_run_script()
38
39 def set_run_script(self):
40 self.pre_run_script = self.opts.pre_run_script
41
42 def set_pre_run_script(self):
43 self.run_script = self.opts.run_script
44
45 def get_remote_for_script(self, script):
46 return os.path.join(self.tmp_dir, script.rpartition('/')[2])
47
48 def copy_script(self, conn, src):
49 remote_path = self.get_remote_for_script(src)
50 copy_paths(conn, {src: remote_path})
51 return remote_path
52
53 def pre_run(self, conn):
54 remote_script = self.copy_script(conn, self.pre_run_script)
55 cmd = remote_script
koder aka kdanilov2c473092015-03-29 17:12:13 +030056 code, out_err = run_over_ssh(conn, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020057 if code != 0:
koder aka kdanilov2c473092015-03-29 17:12:13 +030058 raise Exception("Pre run failed. %s" % out_err)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020059
koder aka kdanilov2c473092015-03-29 17:12:13 +030060 def run(self, conn, barrier):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020061 remote_script = self.copy_script(conn, self.run_script)
Yulia Portnova3f65e7c2015-02-25 17:19:35 +020062 cmd = remote_script + ' ' + ' '.join(self.opts)
koder aka kdanilov2c473092015-03-29 17:12:13 +030063 code, out_err = run_over_ssh(conn, cmd)
64 self.on_result(code, out_err, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020065
66 def parse_results(self, out):
67 for line in out.split("\n"):
68 key, separator, value = line.partition(":")
69 if key and value:
70 self.on_result_cb((key, float(value)))
71
koder aka kdanilov2c473092015-03-29 17:12:13 +030072 def on_result(self, code, out_err, cmd):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020073 if 0 == code:
74 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +030075 self.parse_results(out_err)
76 except Exception as exc:
Yulia Portnova7ddfa732015-02-24 17:32:58 +020077 msg_templ = "Error during postprocessing results: {0!r}"
koder aka kdanilov2c473092015-03-29 17:12:13 +030078 raise RuntimeError(msg_templ.format(exc.message))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020079 else:
80 templ = "Command {0!r} failed with code {1}. Error output is:\n{2}"
koder aka kdanilov2c473092015-03-29 17:12:13 +030081 logger.error(templ.format(cmd, code, out_err))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020082
83
84class PgBenchTest(TwoScriptTest):
85
86 def set_run_script(self):
87 self.pre_run_script = "hl_tests/postgres/prepare.sh"
88
89 def set_pre_run_script(self):
90 self.run_script = "hl_tests/postgres/run.sh"
91
92
koder aka kdanilov4643fd62015-02-10 16:20:13 -080093class IOPerfTest(IPerfTest):
koder aka kdanilovda45e882015-04-06 02:24:42 +030094 io_py_remote = "/tmp/disk_test_agent.py"
koder aka kdanilov2c473092015-03-29 17:12:13 +030095
koder aka kdanilov4643fd62015-02-10 16:20:13 -080096 def __init__(self,
koder aka kdanilov2c473092015-03-29 17:12:13 +030097 test_options,
98 on_result_cb):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080099 IPerfTest.__init__(self, on_result_cb)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300100 self.options = test_options
koder aka kdanilovda45e882015-04-06 02:24:42 +0300101 self.config_fname = test_options['cfg']
102 self.config_params = test_options.get('params', {})
103 self.tool = test_options.get('tool', 'fio')
104 self.raw_cfg = open(self.config_fname).read()
koder aka kdanilov50f18642015-02-11 08:54:44 -0800105
koder aka kdanilovda45e882015-04-06 02:24:42 +0300106 parse_func = disk_test_agent.parse_fio_config_full
107 self.configs = parse_func(self.raw_cfg, self.config_params)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800108
109 def pre_run(self, conn):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300110
111 # TODO: install fio, if not installed
112 run_over_ssh(conn, "apt-get -y install fio")
113
114 local_fname = disk_test_agent.__file__.rsplit('.')[0] + ".py"
koder aka kdanilov2c473092015-03-29 17:12:13 +0300115 self.files_to_copy = {local_fname: self.io_py_remote}
koder aka kdanilov50f18642015-02-11 08:54:44 -0800116 copy_paths(conn, self.files_to_copy)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800117
koder aka kdanilov2c473092015-03-29 17:12:13 +0300118 cmd_templ = "dd if=/dev/zero of={0} bs={1} count={2}"
119 for secname, params in self.configs:
120 sz = ssize_to_b(params['size'])
121 msz = msz = sz / (1024 ** 2)
122 if sz % (1024 ** 2) != 0:
123 msz += 1
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800124
koder aka kdanilov2c473092015-03-29 17:12:13 +0300125 cmd = cmd_templ.format(params['filename'], 1024 ** 2, msz)
126 code, out_err = run_over_ssh(conn, cmd)
127
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800128 if code != 0:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300129 raise RuntimeError("Preparation failed " + out_err)
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800130
koder aka kdanilov2c473092015-03-29 17:12:13 +0300131 def run(self, conn, barrier):
132 cmd_templ = "env python2 {0} --type {1} --json -"
133 cmd = cmd_templ.format(self.io_py_remote, self.tool)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300134 logger.debug("Run {0}".format(cmd))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300135 try:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300136 barrier.wait()
137 code, out_err = run_over_ssh(conn, cmd, stdin_data=self.raw_cfg)
138 self.on_result(code, out_err, cmd)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300139 finally:
140 barrier.exit()
141
142 def on_result(self, code, out_err, cmd):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800143 if 0 == code:
144 try:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300145 start_patt = r"(?ims)=+\s+RESULTS\(format=json\)\s+=+"
146 end_patt = r"(?ims)=+\s+END OF RESULTS\s+=+"
147 for block in re.split(start_patt, out_err)[1:]:
148 data, garbage = re.split(end_patt, block)
149 self.on_result_cb(json.loads(data.strip()))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300150 except Exception as exc:
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800151 msg_templ = "Error during postprocessing results: {0!r}"
koder aka kdanilov2c473092015-03-29 17:12:13 +0300152 raise RuntimeError(msg_templ.format(exc.message))
koder aka kdanilove21d7472015-02-14 19:02:04 -0800153 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300154 templ = "Command {0!r} failed with code {1}. Output is:\n{2}"
155 logger.error(templ.format(cmd, code, out_err))