blob: 6ab3410ec2ae6d209afe305a36664ef8622ff89f [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)
97 except Exception as exc:
98 log("Rally raises exception {0}".format(exc.message))
99 raise
100
101 if 0 != code:
102 templ = "Script returns error! code={0}\n {1}"
103 log(templ.format(code, err.rstrip()))
104 else:
105 log("Test finished")
106 try:
107 try:
108 result = json.loads(out)
109 except:
110 pass
111 else:
112 if '__meta__' in result:
113 add_meta_cb(result.pop('__meta__'))
114 out = json.dumps(result)
115 except Exception as err:
116 log("Error during postprocessing results: {0!r}".format(err))
117
118 return code, out, err
119
120 VMScenario.run_command_over_ssh = closure
121
122 try:
123 yield
124 finally:
125 VMScenario.run_command_over_ssh = orig
126
127
128def run_rally(rally_args):
129 return cliutils.run(['rally'] + rally_args, categories)
130
131
132def prepare_files(iozone_py_argv, dst_iozone_path, files_dir):
133
134 # we do need temporary named files
135 with warnings.catch_warnings():
136 warnings.simplefilter("ignore")
137 py_file = os.tmpnam()
138 yaml_file = os.tmpnam()
139
140 iozone_py_inp_path = os.path.join(files_dir, "iozone.py")
141 py_src_cont = open(iozone_py_inp_path).read()
142 args_repl_rr = r'INSERT_IOZONE_ARGS\(sys\.argv.*?\)'
143 py_dst_cont = re.sub(args_repl_rr, repr(iozone_py_argv), py_src_cont)
144
145 if py_dst_cont == args_repl_rr:
146 log("Can't find replace marker in file {0}".format(iozone_py_inp_path))
147 exit(1)
148
149 yaml_src_cont = open(os.path.join(files_dir, "iozone.yaml")).read()
150 task_params = yaml.load(yaml_src_cont)
151 rcd_params = task_params['VMTasks.boot_runcommand_delete']
152 rcd_params[0]['args']['script'] = py_file
153 yaml_dst_cont = yaml.dump(task_params)
154
155 open(py_file, "w").write(py_dst_cont)
156 open(yaml_file, "w").write(yaml_dst_cont)
157
158 return yaml_file, py_file
159
160
161def run_test(iozone_py_argv, dst_iozone_path, files_dir):
162 iozone_local = os.path.join(files_dir, 'iozone')
163
164 yaml_file, py_file = prepare_files(iozone_py_argv,
165 dst_iozone_path,
166 files_dir)
167
168 config = yaml.load(open(yaml_file).read())
169
170 vm_sec = 'VMTasks.boot_runcommand_delete'
171 concurrency = config[vm_sec][0]['runner']['concurrency']
172
173 max_preparation_time = 300
174
175 try:
176 copy_files = {iozone_local: dst_iozone_path}
177
178 result_queue = multiprocessing.Queue()
179 cb = result_queue.put
180
181 do_patch = patch_VMScenario_run_command_over_ssh
182
183 barrier = get_barrier(concurrency)
184 max_release_time = time.time() + max_preparation_time
185
186 with do_patch(copy_files, cb, barrier, max_release_time):
187 log("Start rally with 'task start {0}'".format(yaml_file))
188 rally_result = run_rally(['task', 'start', yaml_file])
189
190 # while not result_queue.empty():
191 # log("meta = {0!r}\n".format(result_queue.get()))
192
193 return rally_result
194
195 finally:
196 os.unlink(yaml_file)
197 os.unlink(py_file)
198 # store and process meta and results
199
200
201def main(argv):
202 files_dir = '.'
203 dst_iozone_path = '/tmp/iozone'
204 iozone_py_argv = ['-a', 'randwrite',
205 '--iodepth', '2',
206 '--blocksize', '4k',
207 '--iosize', '20M',
208 '--iozone-path', dst_iozone_path,
209 '-d']
210 run_test(iozone_py_argv, dst_iozone_path, files_dir)
211
212# ubuntu cloud image
213# https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
214
215# glance image-create --name 'ubuntu' --disk-format qcow2
216# --container-format bare --is-public true --copy-from
217# https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
218
219if __name__ == '__main__':
220 exit(main(sys.argv))