blob: cdee319ce63e3c55c319b6a36873a0a31be8e7b2 [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 kdanilovd5ed4da2015-05-07 23:33:23 +03004import time
koder aka kdanilov416b87a2015-05-12 00:26:04 +03005import psutil
koder aka kdanilovafd98742015-04-24 01:27:22 +03006import socket
koder aka kdanilove21d7472015-02-14 19:02:04 -08007import logging
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08008import threading
9import contextlib
koder aka kdanilov652cd802015-04-13 12:21:07 +030010import subprocess
koder aka kdanilov4643fd62015-02-10 16:20:13 -080011
koder aka kdanilove21d7472015-02-14 19:02:04 -080012
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030013logger = logging.getLogger("wally")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080014
15
koder aka kdanilov209e85d2015-04-27 23:11:05 +030016def is_ip(data):
17 if data.count('.') != 3:
18 return False
19
20 try:
21 for part in map(int, data.split('.')):
22 if part > 255 or part < 0:
23 raise ValueError()
24 except ValueError:
25 return False
26 return True
27
28
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030029class StopTestError(RuntimeError):
30 def __init__(self, reason, orig_exc=None):
31 RuntimeError.__init__(self, reason)
32 self.orig_exc = orig_exc
33
34
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030035@contextlib.contextmanager
36def log_block(message, exc_logger=None):
37 logger.debug("Starts : " + message)
38 with log_error(message, exc_logger):
39 yield
40 # try:
41 # yield
42 # except Exception as exc:
43 # if isinstance(exc, types) and not isinstance(exc, StopIteration):
44 # templ = "Error during {0} stage: {1!s}"
45 # logger.debug(templ.format(action, exc))
46 # raise
47
48
49class log_error(object):
50 def __init__(self, message, exc_logger=None):
51 self.message = message
52 self.exc_logger = exc_logger
53
54 def __enter__(self):
55 return self
56
57 def __exit__(self, tp, value, traceback):
58 if value is None or isinstance(value, StopTestError):
59 return
60
61 if self.exc_logger is None:
62 exc_logger = sys._getframe(1).f_globals.get('logger', logger)
63 else:
64 exc_logger = self.exc_logger
65
66 exc_logger.exception(self.message, exc_info=(tp, value, traceback))
67 raise StopTestError(self.message, value)
68
69
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030070def check_input_param(is_ok, message):
71 if not is_ok:
72 logger.error(message)
73 raise StopTestError(message)
74
75
koder aka kdanilove06762a2015-03-22 23:32:09 +020076def parse_creds(creds):
77 # parse user:passwd@host
78 user, passwd_host = creds.split(":", 1)
79
80 if '@' not in passwd_host:
81 passwd, host = passwd_host, None
82 else:
83 passwd, host = passwd_host.rsplit('@', 1)
84
85 return user, passwd, host
86
87
koder aka kdanilov2c473092015-03-29 17:12:13 +030088class TaksFinished(Exception):
89 pass
koder aka kdanilov4643fd62015-02-10 16:20:13 -080090
koder aka kdanilov2c473092015-03-29 17:12:13 +030091
92class Barrier(object):
93 def __init__(self, count):
94 self.count = count
95 self.curr_count = 0
96 self.cond = threading.Condition()
97 self.exited = False
98
99 def wait(self, timeout=None):
100 with self.cond:
101 if self.exited:
102 raise TaksFinished()
103
104 self.curr_count += 1
105 if self.curr_count == self.count:
106 self.curr_count = 0
107 self.cond.notify_all()
koder aka kdanilov652cd802015-04-13 12:21:07 +0300108 return True
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800109 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300110 self.cond.wait(timeout=timeout)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300111 return False
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800112
koder aka kdanilov2c473092015-03-29 17:12:13 +0300113 def exit(self):
114 with self.cond:
115 self.exited = True
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800116
117
koder aka kdanilov2c473092015-03-29 17:12:13 +0300118SMAP = dict(k=1024, m=1024 ** 2, g=1024 ** 3, t=1024 ** 4)
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200119
120
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300121def ssize2b(ssize):
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200122 try:
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300123 if isinstance(ssize, (int, long)):
124 return ssize
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200125
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300126 ssize = ssize.lower()
koder aka kdanilov2c473092015-03-29 17:12:13 +0300127 if ssize[-1] in SMAP:
128 return int(ssize[:-1]) * SMAP[ssize[-1]]
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200129 return int(ssize)
130 except (ValueError, TypeError, AttributeError):
koder aka kdanilov2e928022015-04-08 13:47:15 +0300131 raise ValueError("Unknow size format {0!r}".format(ssize))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300132
133
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300134RSMAP = [('K', 1024),
135 ('M', 1024 ** 2),
136 ('G', 1024 ** 3),
137 ('T', 1024 ** 4)]
138
139
140def b2ssize(size):
141 if size < 1024:
142 return str(size)
143
144 for name, scale in RSMAP:
145 if size < 1024 * scale:
146 if size % scale == 0:
147 return "{0} {1}i".format(size // scale, name)
148 else:
149 return "{0:.1f} {1}i".format(float(size) / scale, name)
150
151 return "{0}{1}i".format(size // scale, name)
152
153
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300154RSMAP_10 = [('k', 1000),
155 ('m', 1000 ** 2),
156 ('g', 1000 ** 3),
157 ('t', 1000 ** 4)]
158
159
160def b2ssize_10(size):
161 if size < 1000:
162 return str(size)
163
164 for name, scale in RSMAP_10:
165 if size < 1000 * scale:
166 if size % scale == 0:
167 return "{0} {1}".format(size // scale, name)
168 else:
169 return "{0:.1f} {1}".format(float(size) / scale, name)
170
171 return "{0}{1}".format(size // scale, name)
172
173
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300174def run_locally(cmd, input_data="", timeout=20):
175 shell = isinstance(cmd, basestring)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300176 proc = subprocess.Popen(cmd,
177 shell=shell,
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300178 stdin=subprocess.PIPE,
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300179 stdout=subprocess.PIPE,
180 stderr=subprocess.PIPE)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300181 res = []
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300182
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300183 def thread_func():
184 rr = proc.communicate(input_data)
185 res.extend(rr)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300186
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300187 thread = threading.Thread(target=thread_func)
188 thread.daemon = True
189 thread.start()
190 thread.join(timeout)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300191
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300192 if thread.is_alive():
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300193
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300194 parent = psutil.Process(proc.pid)
195 for child in parent.children(recursive=True):
196 child.kill()
197 parent.kill()
198 thread.join()
199 raise RuntimeError("Local process timeout: " + str(cmd))
200
201 out, err = res
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300202 if 0 != proc.returncode:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300203 raise subprocess.CalledProcessError(proc.returncode,
204 cmd, out + err)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300205
206 return out
207
208
koder aka kdanilov652cd802015-04-13 12:21:07 +0300209def get_ip_for_target(target_ip):
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300210 if not is_ip(target_ip):
koder aka kdanilovafd98742015-04-24 01:27:22 +0300211 target_ip = socket.gethostbyname(target_ip)
212
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300213 first_dig = map(int, target_ip.split("."))
214 if first_dig == 127:
koder aka kdanilovafd98742015-04-24 01:27:22 +0300215 return '127.0.0.1'
216
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300217 data = run_locally('ip route get to'.split(" ") + [target_ip])
koder aka kdanilov652cd802015-04-13 12:21:07 +0300218
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300219 rr1 = r'{0} via [.0-9]+ dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
220 rr1 = rr1.replace(" ", r'\s+')
221 rr1 = rr1.format(target_ip.replace('.', r'\.'))
222
223 rr2 = r'{0} dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
224 rr2 = rr2.replace(" ", r'\s+')
225 rr2 = rr2.format(target_ip.replace('.', r'\.'))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300226
227 data_line = data.split("\n")[0].strip()
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300228 res1 = re.match(rr1, data_line)
229 res2 = re.match(rr2, data_line)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300230
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300231 if res1 is not None:
232 return res1.group('ip')
koder aka kdanilov652cd802015-04-13 12:21:07 +0300233
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300234 if res2 is not None:
235 return res2.group('ip')
236
237 raise OSError("Can't define interface for {0}".format(target_ip))
238
239
240def open_for_append_or_create(fname):
241 if not os.path.exists(fname):
242 return open(fname, "w")
243
244 fd = open(fname, 'r+')
245 fd.seek(0, os.SEEK_END)
246 return fd
247
248
249def sec_to_str(seconds):
250 h = seconds // 3600
251 m = (seconds % 3600) // 60
252 s = seconds % 60
253 return "{0}:{1:02d}:{2:02d}".format(h, m, s)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300254
255
256def yamable(data):
257 if isinstance(data, (tuple, list)):
258 return map(yamable, data)
259
260 if isinstance(data, unicode):
261 return str(data)
262
263 if isinstance(data, dict):
264 res = {}
265 for k, v in data.items():
266 res[yamable(k)] = yamable(v)
267 return res
268
269 return data
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300270
271
272CLEANING = []
273
274
275def clean_resource(func, *args, **kwargs):
276 CLEANING.append((func, args, kwargs))
277
278
279def iter_clean_func():
280 while CLEANING != []:
281 yield CLEANING.pop()
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300282
283
284def flatten(data):
285 res = []
286 for i in data:
287 if isinstance(i, (list, tuple, set)):
288 res.extend(flatten(i))
289 else:
290 res.append(i)
291 return res