blob: 61c412437a213b64d0596dbabb8e6aebece0c50f [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):
Yulia Portnova886a2562015-04-07 11:16:13 +030030 def __init__(self, opts, on_result_cb):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020031 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 Portnova886a2562015-04-07 11:16:13 +030062 cmd_opts = ' '.join(["%s %s" % (key, val) for key, val
63 in self.opts.items()])
64 cmd = remote_script + ' ' + cmd_opts
koder aka kdanilov2c473092015-03-29 17:12:13 +030065 code, out_err = run_over_ssh(conn, cmd)
66 self.on_result(code, out_err, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020067
68 def parse_results(self, out):
69 for line in out.split("\n"):
70 key, separator, value = line.partition(":")
71 if key and value:
72 self.on_result_cb((key, float(value)))
73
koder aka kdanilov2c473092015-03-29 17:12:13 +030074 def on_result(self, code, out_err, cmd):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020075 if 0 == code:
76 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +030077 self.parse_results(out_err)
78 except Exception as exc:
Yulia Portnova7ddfa732015-02-24 17:32:58 +020079 msg_templ = "Error during postprocessing results: {0!r}"
koder aka kdanilov2c473092015-03-29 17:12:13 +030080 raise RuntimeError(msg_templ.format(exc.message))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020081 else:
82 templ = "Command {0!r} failed with code {1}. Error output is:\n{2}"
koder aka kdanilov2c473092015-03-29 17:12:13 +030083 logger.error(templ.format(cmd, code, out_err))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020084
85
86class PgBenchTest(TwoScriptTest):
87
88 def set_run_script(self):
Yulia Portnova886a2562015-04-07 11:16:13 +030089 self.pre_run_script = "tests/postgres/prepare.sh"
Yulia Portnova7ddfa732015-02-24 17:32:58 +020090
91 def set_pre_run_script(self):
Yulia Portnova886a2562015-04-07 11:16:13 +030092 self.run_script = "tests/postgres/run.sh"
Yulia Portnova7ddfa732015-02-24 17:32:58 +020093
94
koder aka kdanilov4643fd62015-02-10 16:20:13 -080095class IOPerfTest(IPerfTest):
koder aka kdanilovda45e882015-04-06 02:24:42 +030096 io_py_remote = "/tmp/disk_test_agent.py"
koder aka kdanilov2c473092015-03-29 17:12:13 +030097
koder aka kdanilov4643fd62015-02-10 16:20:13 -080098 def __init__(self,
koder aka kdanilov2c473092015-03-29 17:12:13 +030099 test_options,
100 on_result_cb):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800101 IPerfTest.__init__(self, on_result_cb)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300102 self.options = test_options
koder aka kdanilovda45e882015-04-06 02:24:42 +0300103 self.config_fname = test_options['cfg']
104 self.config_params = test_options.get('params', {})
105 self.tool = test_options.get('tool', 'fio')
106 self.raw_cfg = open(self.config_fname).read()
koder aka kdanilov50f18642015-02-11 08:54:44 -0800107
koder aka kdanilovda45e882015-04-06 02:24:42 +0300108 parse_func = disk_test_agent.parse_fio_config_full
109 self.configs = parse_func(self.raw_cfg, self.config_params)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800110
111 def pre_run(self, conn):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300112
113 # TODO: install fio, if not installed
114 run_over_ssh(conn, "apt-get -y install fio")
115
116 local_fname = disk_test_agent.__file__.rsplit('.')[0] + ".py"
koder aka kdanilov2c473092015-03-29 17:12:13 +0300117 self.files_to_copy = {local_fname: self.io_py_remote}
koder aka kdanilov50f18642015-02-11 08:54:44 -0800118 copy_paths(conn, self.files_to_copy)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800119
koder aka kdanilov2c473092015-03-29 17:12:13 +0300120 cmd_templ = "dd if=/dev/zero of={0} bs={1} count={2}"
121 for secname, params in self.configs:
122 sz = ssize_to_b(params['size'])
123 msz = msz = sz / (1024 ** 2)
124 if sz % (1024 ** 2) != 0:
125 msz += 1
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800126
koder aka kdanilov2c473092015-03-29 17:12:13 +0300127 cmd = cmd_templ.format(params['filename'], 1024 ** 2, msz)
128 code, out_err = run_over_ssh(conn, cmd)
129
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800130 if code != 0:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300131 raise RuntimeError("Preparation failed " + out_err)
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800132
koder aka kdanilov2c473092015-03-29 17:12:13 +0300133 def run(self, conn, barrier):
134 cmd_templ = "env python2 {0} --type {1} --json -"
135 cmd = cmd_templ.format(self.io_py_remote, self.tool)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300136 logger.debug("Run {0}".format(cmd))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300137 try:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300138 barrier.wait()
139 code, out_err = run_over_ssh(conn, cmd, stdin_data=self.raw_cfg)
140 self.on_result(code, out_err, cmd)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300141 finally:
142 barrier.exit()
143
144 def on_result(self, code, out_err, cmd):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800145 if 0 == code:
146 try:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300147 start_patt = r"(?ims)=+\s+RESULTS\(format=json\)\s+=+"
148 end_patt = r"(?ims)=+\s+END OF RESULTS\s+=+"
149 for block in re.split(start_patt, out_err)[1:]:
150 data, garbage = re.split(end_patt, block)
151 self.on_result_cb(json.loads(data.strip()))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300152 except Exception as exc:
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800153 msg_templ = "Error during postprocessing results: {0!r}"
koder aka kdanilov2c473092015-03-29 17:12:13 +0300154 raise RuntimeError(msg_templ.format(exc.message))
koder aka kdanilove21d7472015-02-14 19:02:04 -0800155 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300156 templ = "Command {0!r} failed with code {1}. Output is:\n{2}"
157 logger.error(templ.format(cmd, code, out_err))