blob: 3792ba4fe1c11e75792f0bff92d91612af182b1d [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 kdanilovd5ed4da2015-05-07 23:33:23 +03003import time
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 kdanilove21d7472015-02-14 19:02:04 -080010
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030011logger = logging.getLogger("wally")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080012
13
koder aka kdanilov209e85d2015-04-27 23:11:05 +030014def is_ip(data):
15 if data.count('.') != 3:
16 return False
17
18 try:
19 for part in map(int, data.split('.')):
20 if part > 255 or part < 0:
21 raise ValueError()
22 except ValueError:
23 return False
24 return True
25
26
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030027class StopTestError(RuntimeError):
28 def __init__(self, reason, orig_exc=None):
29 RuntimeError.__init__(self, reason)
30 self.orig_exc = orig_exc
31
32
33def check_input_param(is_ok, message):
34 if not is_ok:
35 logger.error(message)
36 raise StopTestError(message)
37
38
koder aka kdanilove06762a2015-03-22 23:32:09 +020039def parse_creds(creds):
40 # parse user:passwd@host
41 user, passwd_host = creds.split(":", 1)
42
43 if '@' not in passwd_host:
44 passwd, host = passwd_host, None
45 else:
46 passwd, host = passwd_host.rsplit('@', 1)
47
48 return user, passwd, host
49
50
koder aka kdanilov2c473092015-03-29 17:12:13 +030051class TaksFinished(Exception):
52 pass
koder aka kdanilov4643fd62015-02-10 16:20:13 -080053
koder aka kdanilov2c473092015-03-29 17:12:13 +030054
55class Barrier(object):
56 def __init__(self, count):
57 self.count = count
58 self.curr_count = 0
59 self.cond = threading.Condition()
60 self.exited = False
61
62 def wait(self, timeout=None):
63 with self.cond:
64 if self.exited:
65 raise TaksFinished()
66
67 self.curr_count += 1
68 if self.curr_count == self.count:
69 self.curr_count = 0
70 self.cond.notify_all()
koder aka kdanilov652cd802015-04-13 12:21:07 +030071 return True
koder aka kdanilov4643fd62015-02-10 16:20:13 -080072 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +030073 self.cond.wait(timeout=timeout)
koder aka kdanilov652cd802015-04-13 12:21:07 +030074 return False
koder aka kdanilov4643fd62015-02-10 16:20:13 -080075
koder aka kdanilov2c473092015-03-29 17:12:13 +030076 def exit(self):
77 with self.cond:
78 self.exited = True
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080079
80
81@contextlib.contextmanager
82def log_error(action, types=(Exception,)):
83 if not action.startswith("!"):
koder aka kdanilove21d7472015-02-14 19:02:04 -080084 logger.debug("Starts : " + action)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080085 else:
86 action = action[1:]
87
88 try:
89 yield
90 except Exception as exc:
91 if isinstance(exc, types) and not isinstance(exc, StopIteration):
koder aka kdanilovec1b9732015-04-23 20:43:29 +030092 templ = "Error during {0} stage: {1!s}"
93 logger.debug(templ.format(action, exc))
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080094 raise
95
96
koder aka kdanilov2c473092015-03-29 17:12:13 +030097SMAP = dict(k=1024, m=1024 ** 2, g=1024 ** 3, t=1024 ** 4)
koder aka kdanilov8ad6e812015-03-22 14:42:18 +020098
99
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300100def ssize2b(ssize):
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200101 try:
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300102 if isinstance(ssize, (int, long)):
103 return ssize
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200104
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300105 ssize = ssize.lower()
koder aka kdanilov2c473092015-03-29 17:12:13 +0300106 if ssize[-1] in SMAP:
107 return int(ssize[:-1]) * SMAP[ssize[-1]]
koder aka kdanilov8ad6e812015-03-22 14:42:18 +0200108 return int(ssize)
109 except (ValueError, TypeError, AttributeError):
koder aka kdanilov2e928022015-04-08 13:47:15 +0300110 raise ValueError("Unknow size format {0!r}".format(ssize))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300111
112
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300113RSMAP = [('K', 1024),
114 ('M', 1024 ** 2),
115 ('G', 1024 ** 3),
116 ('T', 1024 ** 4)]
117
118
119def b2ssize(size):
120 if size < 1024:
121 return str(size)
122
123 for name, scale in RSMAP:
124 if size < 1024 * scale:
125 if size % scale == 0:
126 return "{0} {1}i".format(size // scale, name)
127 else:
128 return "{0:.1f} {1}i".format(float(size) / scale, name)
129
130 return "{0}{1}i".format(size // scale, name)
131
132
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300133def run_locally(cmd, input_data="", timeout=20):
134 shell = isinstance(cmd, basestring)
135
136 proc = subprocess.Popen(cmd,
137 shell=shell,
138 stdout=subprocess.PIPE,
139 stderr=subprocess.PIPE)
140
141 end_time = time.time() + timeout
142
143 while end_time > time.time():
144 if proc.poll() is None:
145 time.sleep(1)
146
147 out, err = proc.communicate()
148
149 if 0 != proc.returncode:
150 raise subprocess.CalledProcessError(proc.returncode, cmd, out + err)
151
152 return out
153
154
koder aka kdanilov652cd802015-04-13 12:21:07 +0300155def get_ip_for_target(target_ip):
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300156 if not is_ip(target_ip):
koder aka kdanilovafd98742015-04-24 01:27:22 +0300157 target_ip = socket.gethostbyname(target_ip)
158
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300159 first_dig = map(int, target_ip.split("."))
160 if first_dig == 127:
koder aka kdanilovafd98742015-04-24 01:27:22 +0300161 return '127.0.0.1'
162
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300163 data = run_locally('ip route get to'.split(" ") + [target_ip])
koder aka kdanilov652cd802015-04-13 12:21:07 +0300164
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300165 rr1 = r'{0} via [.0-9]+ dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
166 rr1 = rr1.replace(" ", r'\s+')
167 rr1 = rr1.format(target_ip.replace('.', r'\.'))
168
169 rr2 = r'{0} dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
170 rr2 = rr2.replace(" ", r'\s+')
171 rr2 = rr2.format(target_ip.replace('.', r'\.'))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300172
173 data_line = data.split("\n")[0].strip()
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300174 res1 = re.match(rr1, data_line)
175 res2 = re.match(rr2, data_line)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300176
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300177 if res1 is not None:
178 return res1.group('ip')
koder aka kdanilov652cd802015-04-13 12:21:07 +0300179
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300180 if res2 is not None:
181 return res2.group('ip')
182
183 raise OSError("Can't define interface for {0}".format(target_ip))
184
185
186def open_for_append_or_create(fname):
187 if not os.path.exists(fname):
188 return open(fname, "w")
189
190 fd = open(fname, 'r+')
191 fd.seek(0, os.SEEK_END)
192 return fd
193
194
195def sec_to_str(seconds):
196 h = seconds // 3600
197 m = (seconds % 3600) // 60
198 s = seconds % 60
199 return "{0}:{1:02d}:{2:02d}".format(h, m, s)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300200
201
202def yamable(data):
203 if isinstance(data, (tuple, list)):
204 return map(yamable, data)
205
206 if isinstance(data, unicode):
207 return str(data)
208
209 if isinstance(data, dict):
210 res = {}
211 for k, v in data.items():
212 res[yamable(k)] = yamable(v)
213 return res
214
215 return data
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300216
217
218CLEANING = []
219
220
221def clean_resource(func, *args, **kwargs):
222 CLEANING.append((func, args, kwargs))
223
224
225def iter_clean_func():
226 while CLEANING != []:
227 yield CLEANING.pop()