blob: 3792ba4fe1c11e75792f0bff92d91612af182b1d [file] [log] [blame]
import re
import os
import time
import socket
import logging
import threading
import contextlib
import subprocess
logger = logging.getLogger("wally")
def is_ip(data):
if data.count('.') != 3:
return False
try:
for part in map(int, data.split('.')):
if part > 255 or part < 0:
raise ValueError()
except ValueError:
return False
return True
class StopTestError(RuntimeError):
def __init__(self, reason, orig_exc=None):
RuntimeError.__init__(self, reason)
self.orig_exc = orig_exc
def check_input_param(is_ok, message):
if not is_ok:
logger.error(message)
raise StopTestError(message)
def parse_creds(creds):
# parse user:passwd@host
user, passwd_host = creds.split(":", 1)
if '@' not in passwd_host:
passwd, host = passwd_host, None
else:
passwd, host = passwd_host.rsplit('@', 1)
return user, passwd, host
class TaksFinished(Exception):
pass
class Barrier(object):
def __init__(self, count):
self.count = count
self.curr_count = 0
self.cond = threading.Condition()
self.exited = False
def wait(self, timeout=None):
with self.cond:
if self.exited:
raise TaksFinished()
self.curr_count += 1
if self.curr_count == self.count:
self.curr_count = 0
self.cond.notify_all()
return True
else:
self.cond.wait(timeout=timeout)
return False
def exit(self):
with self.cond:
self.exited = True
@contextlib.contextmanager
def log_error(action, types=(Exception,)):
if not action.startswith("!"):
logger.debug("Starts : " + action)
else:
action = action[1:]
try:
yield
except Exception as exc:
if isinstance(exc, types) and not isinstance(exc, StopIteration):
templ = "Error during {0} stage: {1!s}"
logger.debug(templ.format(action, exc))
raise
SMAP = dict(k=1024, m=1024 ** 2, g=1024 ** 3, t=1024 ** 4)
def ssize2b(ssize):
try:
if isinstance(ssize, (int, long)):
return ssize
ssize = ssize.lower()
if ssize[-1] in SMAP:
return int(ssize[:-1]) * SMAP[ssize[-1]]
return int(ssize)
except (ValueError, TypeError, AttributeError):
raise ValueError("Unknow size format {0!r}".format(ssize))
RSMAP = [('K', 1024),
('M', 1024 ** 2),
('G', 1024 ** 3),
('T', 1024 ** 4)]
def b2ssize(size):
if size < 1024:
return str(size)
for name, scale in RSMAP:
if size < 1024 * scale:
if size % scale == 0:
return "{0} {1}i".format(size // scale, name)
else:
return "{0:.1f} {1}i".format(float(size) / scale, name)
return "{0}{1}i".format(size // scale, name)
def run_locally(cmd, input_data="", timeout=20):
shell = isinstance(cmd, basestring)
proc = subprocess.Popen(cmd,
shell=shell,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
end_time = time.time() + timeout
while end_time > time.time():
if proc.poll() is None:
time.sleep(1)
out, err = proc.communicate()
if 0 != proc.returncode:
raise subprocess.CalledProcessError(proc.returncode, cmd, out + err)
return out
def get_ip_for_target(target_ip):
if not is_ip(target_ip):
target_ip = socket.gethostbyname(target_ip)
first_dig = map(int, target_ip.split("."))
if first_dig == 127:
return '127.0.0.1'
data = run_locally('ip route get to'.split(" ") + [target_ip])
rr1 = r'{0} via [.0-9]+ dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
rr1 = rr1.replace(" ", r'\s+')
rr1 = rr1.format(target_ip.replace('.', r'\.'))
rr2 = r'{0} dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
rr2 = rr2.replace(" ", r'\s+')
rr2 = rr2.format(target_ip.replace('.', r'\.'))
data_line = data.split("\n")[0].strip()
res1 = re.match(rr1, data_line)
res2 = re.match(rr2, data_line)
if res1 is not None:
return res1.group('ip')
if res2 is not None:
return res2.group('ip')
raise OSError("Can't define interface for {0}".format(target_ip))
def open_for_append_or_create(fname):
if not os.path.exists(fname):
return open(fname, "w")
fd = open(fname, 'r+')
fd.seek(0, os.SEEK_END)
return fd
def sec_to_str(seconds):
h = seconds // 3600
m = (seconds % 3600) // 60
s = seconds % 60
return "{0}:{1:02d}:{2:02d}".format(h, m, s)
def yamable(data):
if isinstance(data, (tuple, list)):
return map(yamable, data)
if isinstance(data, unicode):
return str(data)
if isinstance(data, dict):
res = {}
for k, v in data.items():
res[yamable(k)] = yamable(v)
return res
return data
CLEANING = []
def clean_resource(func, *args, **kwargs):
CLEANING.append((func, args, kwargs))
def iter_clean_func():
while CLEANING != []:
yield CLEANING.pop()