blob: ab825a6107a7896b56a245d4e51cd5d5ab5d784e [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 kdanilovafd98742015-04-24 01:27:22 +03003import socket
koder aka kdanilove21d7472015-02-14 19:02:04 -08004import logging
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08005import threading
6import contextlib
koder aka kdanilov652cd802015-04-13 12:21:07 +03007import subprocess
koder aka kdanilov4643fd62015-02-10 16:20:13 -08008
koder aka kdanilove21d7472015-02-14 19:02:04 -08009
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030010logger = logging.getLogger("wally")
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080011
12
koder aka kdanilove06762a2015-03-22 23:32:09 +020013def parse_creds(creds):
14 # parse user:passwd@host
15 user, passwd_host = creds.split(":", 1)
16
17 if '@' not in passwd_host:
18 passwd, host = passwd_host, None
19 else:
20 passwd, host = passwd_host.rsplit('@', 1)
21
22 return user, passwd, host
23
24
koder aka kdanilov2c473092015-03-29 17:12:13 +030025class TaksFinished(Exception):
26 pass
koder aka kdanilov4643fd62015-02-10 16:20:13 -080027
koder aka kdanilov2c473092015-03-29 17:12:13 +030028
29class Barrier(object):
30 def __init__(self, count):
31 self.count = count
32 self.curr_count = 0
33 self.cond = threading.Condition()
34 self.exited = False
35
36 def wait(self, timeout=None):
37 with self.cond:
38 if self.exited:
39 raise TaksFinished()
40
41 self.curr_count += 1
42 if self.curr_count == self.count:
43 self.curr_count = 0
44 self.cond.notify_all()
koder aka kdanilov652cd802015-04-13 12:21:07 +030045 return True
koder aka kdanilov4643fd62015-02-10 16:20:13 -080046 else:
koder aka kdanilov2c473092015-03-29 17:12:13 +030047 self.cond.wait(timeout=timeout)
koder aka kdanilov652cd802015-04-13 12:21:07 +030048 return False
koder aka kdanilov4643fd62015-02-10 16:20:13 -080049
koder aka kdanilov2c473092015-03-29 17:12:13 +030050 def exit(self):
51 with self.cond:
52 self.exited = True
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080053
54
55@contextlib.contextmanager
56def log_error(action, types=(Exception,)):
57 if not action.startswith("!"):
koder aka kdanilove21d7472015-02-14 19:02:04 -080058 logger.debug("Starts : " + action)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080059 else:
60 action = action[1:]
61
62 try:
63 yield
64 except Exception as exc:
65 if isinstance(exc, types) and not isinstance(exc, StopIteration):
koder aka kdanilovec1b9732015-04-23 20:43:29 +030066 templ = "Error during {0} stage: {1!s}"
67 logger.debug(templ.format(action, exc))
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080068 raise
69
70
koder aka kdanilov2c473092015-03-29 17:12:13 +030071SMAP = dict(k=1024, m=1024 ** 2, g=1024 ** 3, t=1024 ** 4)
koder aka kdanilov8ad6e812015-03-22 14:42:18 +020072
73
74def ssize_to_b(ssize):
75 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +030076 ssize = ssize.lower()
koder aka kdanilov8ad6e812015-03-22 14:42:18 +020077
koder aka kdanilov2c473092015-03-29 17:12:13 +030078 if ssize.endswith("b"):
79 ssize = ssize[:-1]
80 if ssize[-1] in SMAP:
81 return int(ssize[:-1]) * SMAP[ssize[-1]]
koder aka kdanilov8ad6e812015-03-22 14:42:18 +020082 return int(ssize)
83 except (ValueError, TypeError, AttributeError):
koder aka kdanilov2e928022015-04-08 13:47:15 +030084 raise ValueError("Unknow size format {0!r}".format(ssize))
koder aka kdanilov652cd802015-04-13 12:21:07 +030085
86
87def get_ip_for_target(target_ip):
koder aka kdanilovafd98742015-04-24 01:27:22 +030088 if not re.match("[0-9]+\.[0-9]+\.[0-9]+\.[0-9]$", target_ip):
89 target_ip = socket.gethostbyname(target_ip)
90
91 if target_ip in ('localhost', '127.0.0.1', '127.0.1.1'):
92 return '127.0.0.1'
93
koder aka kdanilov652cd802015-04-13 12:21:07 +030094 cmd = 'ip route get to'.split(" ") + [target_ip]
95 data = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout.read()
96
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030097 rr1 = r'{0} via [.0-9]+ dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
98 rr1 = rr1.replace(" ", r'\s+')
99 rr1 = rr1.format(target_ip.replace('.', r'\.'))
100
101 rr2 = r'{0} dev (?P<dev>.*?) src (?P<ip>[.0-9]+)$'
102 rr2 = rr2.replace(" ", r'\s+')
103 rr2 = rr2.format(target_ip.replace('.', r'\.'))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300104
105 data_line = data.split("\n")[0].strip()
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300106 res1 = re.match(rr1, data_line)
107 res2 = re.match(rr2, data_line)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300108
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300109 if res1 is not None:
110 return res1.group('ip')
koder aka kdanilov652cd802015-04-13 12:21:07 +0300111
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300112 if res2 is not None:
113 return res2.group('ip')
114
115 raise OSError("Can't define interface for {0}".format(target_ip))
116
117
118def open_for_append_or_create(fname):
119 if not os.path.exists(fname):
120 return open(fname, "w")
121
122 fd = open(fname, 'r+')
123 fd.seek(0, os.SEEK_END)
124 return fd
125
126
127def sec_to_str(seconds):
128 h = seconds // 3600
129 m = (seconds % 3600) // 60
130 s = seconds % 60
131 return "{0}:{1:02d}:{2:02d}".format(h, m, s)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300132
133
134def yamable(data):
135 if isinstance(data, (tuple, list)):
136 return map(yamable, data)
137
138 if isinstance(data, unicode):
139 return str(data)
140
141 if isinstance(data, dict):
142 res = {}
143 for k, v in data.items():
144 res[yamable(k)] = yamable(v)
145 return res
146
147 return data