blob: 136200043d63b6f2924b794b19fbb57f252b2513 [file] [log] [blame]
koder aka kdanilov652cd802015-04-13 12:21:07 +03001import re
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03002import os
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +03003import sys
koder aka kdanilovafd98742015-04-24 01:27:22 +03004import socket
koder aka kdanilove21d7472015-02-14 19:02:04 -08005import logging
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08006import threading
7import contextlib
koder aka kdanilov652cd802015-04-13 12:21:07 +03008import subprocess
koder aka kdanilov4643fd62015-02-10 16:20:13 -08009
koder aka kdanilovbb5fe072015-05-21 02:50:23 +030010try:
11 import psutil
12except ImportError:
13 psutil = None
14
koder aka kdanilove21d7472015-02-14 19:02:04 -080015
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030016logger = logging.getLogger("wally")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080017
18
koder aka kdanilov209e85d2015-04-27 23:11:05 +030019def is_ip(data):
20 if data.count('.') != 3:
21 return False
22
23 try:
24 for part in map(int, data.split('.')):
25 if part > 255 or part < 0:
26 raise ValueError()
27 except ValueError:
28 return False
29 return True
30
31
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030032class StopTestError(RuntimeError):
33 def __init__(self, reason, orig_exc=None):
34 RuntimeError.__init__(self, reason)
35 self.orig_exc = orig_exc
36
37
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030038@contextlib.contextmanager
39def log_block(message, exc_logger=None):
40 logger.debug("Starts : " + message)
41 with log_error(message, exc_logger):
42 yield
43 # try:
44 # yield
45 # except Exception as exc:
46 # if isinstance(exc, types) and not isinstance(exc, StopIteration):
47 # templ = "Error during {0} stage: {1!s}"
48 # logger.debug(templ.format(action, exc))
49 # raise
50
51
52class log_error(object):
53 def __init__(self, message, exc_logger=None):
54 self.message = message
55 self.exc_logger = exc_logger
56
57 def __enter__(self):
58 return self
59
60 def __exit__(self, tp, value, traceback):
61 if value is None or isinstance(value, StopTestError):
62 return
63
64 if self.exc_logger is None:
65 exc_logger = sys._getframe(1).f_globals.get('logger', logger)
66 else:
67 exc_logger = self.exc_logger
68
69 exc_logger.exception(self.message, exc_info=(tp, value, traceback))
70 raise StopTestError(self.message, value)
71
72
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030073def check_input_param(is_ok, message):
74 if not is_ok:
75 logger.error(message)
76 raise StopTestError(message)
77
78
koder aka kdanilove06762a2015-03-22 23:32:09 +020079def parse_creds(creds):
80 # parse user:passwd@host
81 user, passwd_host = creds.split(":", 1)
82
83 if '@' not in passwd_host:
84 passwd, host = passwd_host, None
85 else:
86 passwd, host = passwd_host.rsplit('@', 1)
87
88 return user, passwd, host
89
90
koder aka kdanilov2c473092015-03-29 17:12:13 +030091class TaksFinished(Exception):
92 pass
koder aka kdanilov4643fd62015-02-10 16:20:13 -080093
koder aka kdanilov2c473092015-03-29 17:12:13 +030094
95class Barrier(object):
96 def __init__(self, count):
97 self.count = count
98 self.curr_count = 0
99 self.cond = threading.Condition()
100 self.exited = False
101
102 def wait(self, timeout=None):
103 with self.cond:
104 if self.exited:
105 raise TaksFinished()
106
107 self.curr_count += 1
108 if self.curr_count == self.count:
109 self.curr_count = 0
110 self.cond.notify_all()
koder aka kdanilov652cd802015-04-13 12:21:07 +0300111 return True
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800112 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300113 self.cond.wait(timeout=timeout)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300114 return False
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800115
koder aka kdanilov2c473092015-03-29 17:12:13 +0300116 def exit(self):
117 with self.cond:
118 self.exited = True
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800119
120
koder aka kdanilov2c473092015-03-29 17:12:13 +0300121SMAP = dict(k=1024, m=1024 ** 2, g=1024 ** 3, t=1024 ** 4)
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200122
123
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300124def ssize2b(ssize):
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200125 try:
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300126 if isinstance(ssize, (int, long)):
127 return ssize
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200128
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300129 ssize = ssize.lower()
koder aka kdanilov2c473092015-03-29 17:12:13 +0300130 if ssize[-1] in SMAP:
131 return int(ssize[:-1]) * SMAP[ssize[-1]]
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200132 return int(ssize)
133 except (ValueError, TypeError, AttributeError):
koder aka kdanilov2e928022015-04-08 13:47:15 +0300134 raise ValueError("Unknow size format {0!r}".format(ssize))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300135
136
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300137RSMAP = [('K', 1024),
138 ('M', 1024 ** 2),
139 ('G', 1024 ** 3),
140 ('T', 1024 ** 4)]
141
142
143def b2ssize(size):
144 if size < 1024:
145 return str(size)
146
147 for name, scale in RSMAP:
148 if size < 1024 * scale:
149 if size % scale == 0:
150 return "{0} {1}i".format(size // scale, name)
151 else:
152 return "{0:.1f} {1}i".format(float(size) / scale, name)
153
154 return "{0}{1}i".format(size // scale, name)
155
156
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300157RSMAP_10 = [('k', 1000),
158 ('m', 1000 ** 2),
159 ('g', 1000 ** 3),
160 ('t', 1000 ** 4)]
161
162
163def b2ssize_10(size):
164 if size < 1000:
165 return str(size)
166
167 for name, scale in RSMAP_10:
168 if size < 1000 * scale:
169 if size % scale == 0:
170 return "{0} {1}".format(size // scale, name)
171 else:
172 return "{0:.1f} {1}".format(float(size) / scale, name)
173
174 return "{0}{1}".format(size // scale, name)
175
176
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300177def run_locally(cmd, input_data="", timeout=20):
178 shell = isinstance(cmd, basestring)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300179 proc = subprocess.Popen(cmd,
180 shell=shell,
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300181 stdin=subprocess.PIPE,
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300182 stdout=subprocess.PIPE,
183 stderr=subprocess.PIPE)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300184 res = []
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300185
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300186 def thread_func():
187 rr = proc.communicate(input_data)
188 res.extend(rr)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300189
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300190 thread = threading.Thread(target=thread_func,
191 name="Local cmd execution")
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300192 thread.daemon = True
193 thread.start()
194 thread.join(timeout)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300195
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300196 if thread.is_alive():
koder aka kdanilovbb5fe072015-05-21 02:50:23 +0300197 if psutil is not None:
198 parent = psutil.Process(proc.pid)
199 for child in parent.children(recursive=True):
200 child.kill()
201 parent.kill()
202 else:
203 proc.kill()
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300204
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300205 thread.join()
206 raise RuntimeError("Local process timeout: " + str(cmd))
207
208 out, err = res
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300209 if 0 != proc.returncode:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300210 raise subprocess.CalledProcessError(proc.returncode,
211 cmd, out + err)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300212
213 return out
214
215
koder aka kdanilov652cd802015-04-13 12:21:07 +0300216def get_ip_for_target(target_ip):
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300217 if not is_ip(target_ip):
koder aka kdanilovafd98742015-04-24 01:27:22 +0300218 target_ip = socket.gethostbyname(target_ip)
219
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300220 first_dig = map(int, target_ip.split("."))
221 if first_dig == 127:
koder aka kdanilovafd98742015-04-24 01:27:22 +0300222 return '127.0.0.1'
223
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300224 data = run_locally('ip route get to'.split(" ") + [target_ip])
koder aka kdanilov652cd802015-04-13 12:21:07 +0300225
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300226 rr1 = r'{0} via [.0-9]+ dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
227 rr1 = rr1.replace(" ", r'\s+')
228 rr1 = rr1.format(target_ip.replace('.', r'\.'))
229
230 rr2 = r'{0} dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
231 rr2 = rr2.replace(" ", r'\s+')
232 rr2 = rr2.format(target_ip.replace('.', r'\.'))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300233
234 data_line = data.split("\n")[0].strip()
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300235 res1 = re.match(rr1, data_line)
236 res2 = re.match(rr2, data_line)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300237
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300238 if res1 is not None:
239 return res1.group('ip')
koder aka kdanilov652cd802015-04-13 12:21:07 +0300240
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300241 if res2 is not None:
242 return res2.group('ip')
243
244 raise OSError("Can't define interface for {0}".format(target_ip))
245
246
247def open_for_append_or_create(fname):
248 if not os.path.exists(fname):
249 return open(fname, "w")
250
251 fd = open(fname, 'r+')
252 fd.seek(0, os.SEEK_END)
253 return fd
254
255
256def sec_to_str(seconds):
257 h = seconds // 3600
258 m = (seconds % 3600) // 60
259 s = seconds % 60
260 return "{0}:{1:02d}:{2:02d}".format(h, m, s)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300261
262
263def yamable(data):
264 if isinstance(data, (tuple, list)):
265 return map(yamable, data)
266
267 if isinstance(data, unicode):
268 return str(data)
269
270 if isinstance(data, dict):
271 res = {}
272 for k, v in data.items():
273 res[yamable(k)] = yamable(v)
274 return res
275
276 return data
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300277
278
279CLEANING = []
280
281
282def clean_resource(func, *args, **kwargs):
283 CLEANING.append((func, args, kwargs))
284
285
286def iter_clean_func():
287 while CLEANING != []:
288 yield CLEANING.pop()
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300289
290
291def flatten(data):
292 res = []
293 for i in data:
294 if isinstance(i, (list, tuple, set)):
295 res.extend(flatten(i))
296 else:
297 res.append(i)
298 return res
koder aka kdanilov89fb6102015-06-13 02:58:08 +0300299
300
301def get_creds_openrc(path):
302 fc = open(path).read()
303
304 echo = 'echo "$OS_TENANT_NAME:$OS_USERNAME:$OS_PASSWORD@$OS_AUTH_URL"'
305
306 msg = "Failed to get creads from openrc file"
307 with log_error(msg):
308 data = run_locally(['/bin/bash'], input_data=fc + "\n" + echo)
309
310 msg = "Failed to get creads from openrc file: " + data
311 with log_error(msg):
312 data = data.strip()
313 user, tenant, passwd_auth_url = data.split(':', 2)
314 passwd, auth_url = passwd_auth_url.rsplit("@", 1)
315 assert (auth_url.startswith("https://") or
316 auth_url.startswith("http://"))
317
318 return user, passwd, tenant, auth_url
319
320
321def get_os(run_func):
322 try:
323 run_func("ls -l /etc/redhat-release")
324 return 'redhat'
325 except:
326 pass
327
328 try:
329 run_func("ls -l /etc/debian-release")
330 return 'ubuntu'
331 except:
332 pass
333
334 raise RuntimeError("Unknown os")