blob: 90051fb0833e9ddc5239ed522aabc2963d89d8cd [file] [log] [blame]
koder aka kdanilov4643fd62015-02-10 16:20:13 -08001import os
2import json
3import time
4import yaml
koder aka kdanilov36d48a62015-02-15 07:44:00 -08005import logging
koder aka kdanilov4643fd62015-02-10 16:20:13 -08006import warnings
7import functools
8import contextlib
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08009import multiprocessing
koder aka kdanilov4643fd62015-02-10 16:20:13 -080010
11from rally import exceptions
12from rally.cmd import cliutils
13from rally.cmd.main import categories
14from rally.benchmark.scenarios.vm.utils import VMScenario
15from rally.benchmark.scenarios.vm.vmtasks import VMTasks
16
17import itest
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080018from utils import get_barrier, wait_on_barrier
koder aka kdanilov4643fd62015-02-10 16:20:13 -080019
20
koder aka kdanilov36d48a62015-02-15 07:44:00 -080021log = logging.getLogger("io-perf-tool").debug
22
23
koder aka kdanilov4643fd62015-02-10 16:20:13 -080024@contextlib.contextmanager
25def patch_VMTasks_boot_runcommand_delete():
26
27 try:
28 orig = VMTasks.boot_runcommand_delete
29 except AttributeError:
30 # rally code was changed
31 log("VMTasks class was changed and have no boot_runcommand_delete"
32 " method anymore. Update patch code.")
33 raise exceptions.ScriptError("monkeypatch code fails on "
34 "VMTasks.boot_runcommand_delete")
35
36 @functools.wraps(orig)
37 def new_boot_runcommand_delete(self, *args, **kwargs):
38 if 'rally_affinity_group' in os.environ:
39 group_id = os.environ['rally_affinity_group']
40 kwargs['scheduler_hints'] = {'group': group_id}
41 return orig(self, *args, **kwargs)
42
43 VMTasks.boot_runcommand_delete = new_boot_runcommand_delete
44
45 try:
46 yield
47 finally:
48 VMTasks.boot_runcommand_delete = orig
49
50
51# should actually use mock module for this,
52# but don't wanna to add new dependency
53@contextlib.contextmanager
54def patch_VMScenario_run_command_over_ssh(test_obj,
55 barrier=None,
56 latest_start_time=None):
57
58 try:
59 orig = VMScenario.run_action
60 except AttributeError:
61 # rally code was changed
62 log("VMScenario class was changed and have no run_action"
63 " method anymore. Update patch code.")
64 raise exceptions.ScriptError("monkeypatch code fails on "
65 "VMScenario.run_action")
66
67 @functools.wraps(orig)
68 def closure(self, ssh, *args, **kwargs):
koder aka kdanilov50f18642015-02-11 08:54:44 -080069
koder aka kdanilov4643fd62015-02-10 16:20:13 -080070 try:
71 ssh._client.open_sftp
72 except AttributeError:
73 # rally code was changed
74 log("Prototype of VMScenario.run_command_over_ssh "
75 "was changed. Update patch code.")
76 raise exceptions.ScriptError("monkeypatch code fails on "
77 "ssh._client.open_sftp()")
78
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080079 test_iter = itest.run_test_iter(test_obj, ssh._get_client())
koder aka kdanilov4643fd62015-02-10 16:20:13 -080080
81 next(test_iter)
82
83 log("Start io test")
84
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080085 wait_on_barrier(barrier, latest_start_time)
koder aka kdanilov4643fd62015-02-10 16:20:13 -080086
87 try:
88 code, out, err = next(test_iter)
89 except Exception as exc:
90 log("Rally raises exception {0}".format(exc.message))
91 raise
92
93 if 0 != code:
94 templ = "Script returns error! code={0}\n {1}"
95 log(templ.format(code, err.rstrip()))
96 else:
97 log("Test finished")
98
koder aka kdanilov4643fd62015-02-10 16:20:13 -080099 result = {"rally": 0}
100 out = json.dumps(result)
101
102 return code, out, err
103
104 VMScenario.run_action = closure
105
106 try:
107 yield
108 finally:
109 VMScenario.run_action = orig
110
111
koder aka kdanilov50f18642015-02-11 08:54:44 -0800112def prepare_files(files_dir):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800113
114 # we do need temporary named files
115 with warnings.catch_warnings():
116 warnings.simplefilter("ignore")
117 yaml_file = os.tmpnam()
118
119 yaml_src_cont = open(os.path.join(files_dir, "io.yaml")).read()
120 task_params = yaml.load(yaml_src_cont)
121 rcd_params = task_params['VMTasks.boot_runcommand_delete']
122 rcd_params[0]['args']['script'] = os.path.join(files_dir, "io.py")
123 yaml_dst_cont = yaml.dump(task_params)
124
125 open(yaml_file, "w").write(yaml_dst_cont)
126
127 return yaml_file
128
129
130def run_tests_using_rally(obj,
131 files_dir,
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800132 max_preparation_time,
133 rally_extra_opts,
134 keep_temp_files):
135
koder aka kdanilov50f18642015-02-11 08:54:44 -0800136 yaml_file = prepare_files(files_dir)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800137
138 try:
139 do_patch1 = patch_VMScenario_run_command_over_ssh
140 config = yaml.load(open(yaml_file).read())
141
142 vm_sec = 'VMTasks.boot_runcommand_delete'
143 concurrency = config[vm_sec][0]['runner']['concurrency']
144
145 barrier = get_barrier(concurrency)
146 max_release_time = time.time() + max_preparation_time
147
148 with patch_VMTasks_boot_runcommand_delete():
149 with do_patch1(obj, barrier, max_release_time):
150 opts = ['task', 'start', yaml_file] + list(rally_extra_opts)
151 log("Start rally with opts '{0}'".format(" ".join(opts)))
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800152 cliutils.run(['rally', "--rally-debug"] + opts, categories)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800153 finally:
154 if not keep_temp_files:
155 os.unlink(yaml_file)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800156
157
158def get_rally_runner(files_dir,
159 max_preparation_time,
160 rally_extra_opts,
161 keep_temp_files):
162
163 def closure(obj):
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800164 result_queue = multiprocessing.Queue()
165 obj.set_result_cb(result_queue.put)
166
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800167 run_tests_using_rally(obj,
168 files_dir,
169 max_preparation_time,
170 rally_extra_opts,
171 keep_temp_files)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800172
173 test_result = []
174 while not result_queue.empty():
175 test_result.append(result_queue.get())
176
177 return test_result
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800178 return closure