blob: dc3a89a864934c870210d4acee555dfbc8b63bea [file] [log] [blame]
koder aka kdanilov4af80852015-02-01 23:36:38 +02001import os
2import re
3import sys
4import time
5import yaml
6import json
7import os.path
8import datetime
9import warnings
10import functools
11import contextlib
12import multiprocessing
13
14from rally import exceptions
15from rally.cmd import cliutils
16from rally.cmd.main import categories
17from rally.benchmark.scenarios.vm.utils import VMScenario
18
19
20def log(x):
21 dt_str = datetime.datetime.now().strftime("%H:%M:%S")
22 pref = dt_str + " " + str(os.getpid()) + " >>>> "
23 sys.stderr.write(pref + x.replace("\n", "\n" + pref) + "\n")
24
25
26def get_barrier(count):
27 val = multiprocessing.Value('i', count)
28 cond = multiprocessing.Condition()
29
30 def closure(timeout):
31 with cond:
32 val.value -= 1
33
34 log("barrier value == {0}".format(val.value))
35
36 if val.value == 0:
37 cond.notify_all()
38 else:
39 cond.wait(timeout)
40 return val.value == 0
41
42 return closure
43
44
45MAX_WAIT_TOUT = 60
46
47
48@contextlib.contextmanager
49def patch_VMScenario_run_command_over_ssh(paths,
50 add_meta_cb,
51 barrier=None,
52 latest_start_time=None):
53
54 orig = VMScenario.run_command_over_ssh
55
56 @functools.wraps(orig)
57 def closure(self, ssh, *args, **kwargs):
58 try:
59 sftp = ssh._client.open_sftp()
60 except AttributeError:
61 # rally code was changed
62 log("Prototype of VMScenario.run_command_over_ssh "
63 "was changed. Update patch code.")
64 raise exceptions.ScriptError("monkeypath code fails on "
65 "ssh._client.open_sftp()")
66
67 for src, dst in paths.items():
68 try:
69 sftp.put(src, dst)
70 except Exception as exc:
71 tmpl = "Scp {0!r} => {1!r} failed - {2!r}"
72 msg = tmpl.format(src, dst, exc)
73 log(msg)
74 raise exceptions.ScriptError(
75 "monkeypath code fails on " + msg)
76
77 sftp.close()
78
79 log("Start io test")
80
81 if barrier is not None:
82 if latest_start_time is not None:
83 timeout = latest_start_time - time.time()
84 else:
85 timeout = None
86
87 if timeout is not None and timeout > 0:
88 msg = "Ready and waiting on barrier. " + \
89 "Will wait at most {0} seconds"
90 log(msg.format(int(timeout)))
91
92 if not barrier(timeout):
93 log("Barrier timeouted")
94
95 try:
96 code, out, err = orig(self, ssh, *args, **kwargs)
koder aka kdanilov98615bf2015-02-02 00:59:07 +020097 log("!!!!!!!!!!!!!!!!!!!! {} {} {}".format(code, out, err))
koder aka kdanilov4af80852015-02-01 23:36:38 +020098 except Exception as exc:
99 log("Rally raises exception {0}".format(exc.message))
100 raise
101
102 if 0 != code:
103 templ = "Script returns error! code={0}\n {1}"
104 log(templ.format(code, err.rstrip()))
105 else:
106 log("Test finished")
107 try:
108 try:
109 result = json.loads(out)
110 except:
111 pass
112 else:
113 if '__meta__' in result:
114 add_meta_cb(result.pop('__meta__'))
115 out = json.dumps(result)
116 except Exception as err:
117 log("Error during postprocessing results: {0!r}".format(err))
118
119 return code, out, err
120
121 VMScenario.run_command_over_ssh = closure
122
123 try:
124 yield
125 finally:
126 VMScenario.run_command_over_ssh = orig
127
128
129def run_rally(rally_args):
130 return cliutils.run(['rally'] + rally_args, categories)
131
132
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200133def prepare_files(testtool_py_argv, dst_testtool_path, files_dir):
koder aka kdanilov4af80852015-02-01 23:36:38 +0200134
135 # we do need temporary named files
136 with warnings.catch_warnings():
137 warnings.simplefilter("ignore")
138 py_file = os.tmpnam()
139 yaml_file = os.tmpnam()
140
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200141 testtool_py_inp_path = os.path.join(files_dir, "io.py")
142 py_src_cont = open(testtool_py_inp_path).read()
143 args_repl_rr = r'INSERT_TOOL_ARGS\(sys\.argv.*?\)'
144 py_dst_cont = re.sub(args_repl_rr, repr(testtool_py_argv), py_src_cont)
koder aka kdanilov4af80852015-02-01 23:36:38 +0200145
146 if py_dst_cont == args_repl_rr:
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200147 templ = "Can't find replace marker in file {0}"
148 log(templ.format(testtool_py_inp_path))
koder aka kdanilov4af80852015-02-01 23:36:38 +0200149 exit(1)
150
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200151 yaml_src_cont = open(os.path.join(files_dir, "io.yaml")).read()
koder aka kdanilov4af80852015-02-01 23:36:38 +0200152 task_params = yaml.load(yaml_src_cont)
153 rcd_params = task_params['VMTasks.boot_runcommand_delete']
154 rcd_params[0]['args']['script'] = py_file
155 yaml_dst_cont = yaml.dump(task_params)
156
157 open(py_file, "w").write(py_dst_cont)
158 open(yaml_file, "w").write(yaml_dst_cont)
159
160 return yaml_file, py_file
161
162
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200163def run_test(tool, testtool_py_argv, dst_testtool_path, files_dir):
164 path = 'iozone' if 'iozone' == tool else 'fio'
165 testtool_local = os.path.join(files_dir, path)
koder aka kdanilov4af80852015-02-01 23:36:38 +0200166
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200167 yaml_file, py_file = prepare_files(testtool_py_argv,
168 dst_testtool_path,
koder aka kdanilov4af80852015-02-01 23:36:38 +0200169 files_dir)
170
171 config = yaml.load(open(yaml_file).read())
172
173 vm_sec = 'VMTasks.boot_runcommand_delete'
174 concurrency = config[vm_sec][0]['runner']['concurrency']
175
176 max_preparation_time = 300
177
178 try:
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200179 copy_files = {testtool_local: dst_testtool_path}
koder aka kdanilov4af80852015-02-01 23:36:38 +0200180
181 result_queue = multiprocessing.Queue()
182 cb = result_queue.put
183
184 do_patch = patch_VMScenario_run_command_over_ssh
185
186 barrier = get_barrier(concurrency)
187 max_release_time = time.time() + max_preparation_time
188
189 with do_patch(copy_files, cb, barrier, max_release_time):
190 log("Start rally with 'task start {0}'".format(yaml_file))
191 rally_result = run_rally(['task', 'start', yaml_file])
192
193 # while not result_queue.empty():
194 # log("meta = {0!r}\n".format(result_queue.get()))
195
196 return rally_result
197
198 finally:
199 os.unlink(yaml_file)
200 os.unlink(py_file)
201 # store and process meta and results
202
203
204def main(argv):
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200205 tool_type = argv[0]
206 files_dir = argv[1]
207
208 dst_testtool_path = '/tmp/io_tool'
209
210 testtool_py_argv = ['--type', tool_type,
211 '-a', 'randwrite',
212 '--iodepth', '2',
213 '--blocksize', '4k',
214 '--iosize', '20M',
215 '--binary-path', dst_testtool_path,
216 '-d']
217 run_test(tool_type, testtool_py_argv, dst_testtool_path, files_dir)
koder aka kdanilov4af80852015-02-01 23:36:38 +0200218
219# ubuntu cloud image
220# https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
221
222# glance image-create --name 'ubuntu' --disk-format qcow2
223# --container-format bare --is-public true --copy-from
224# https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
225
226if __name__ == '__main__':
koder aka kdanilov98615bf2015-02-02 00:59:07 +0200227 exit(main(sys.argv[1:]))