]>
Commit | Line | Data |
---|---|---|
dfff8bd5 MM |
1 | # vi: encoding=utf-8 ts=8 sts=4 sw=4 et |
2 | ||
4dd00642 MM |
3 | import glob |
4 | import re | |
5 | import string | |
6 | import os | |
7 | import time | |
8 | import shutil | |
63212346 | 9 | import sys |
a170e629 | 10 | import traceback |
63319e0a | 11 | import urllib2 |
4dd00642 | 12 | |
4dd00642 MM |
13 | from config import config, init_conf |
14 | import mailer | |
15 | import path | |
0ea52c57 | 16 | import log |
3f446d8f | 17 | import loop |
0ea52c57 | 18 | import status |
3f446d8f | 19 | import lock |
4dd00642 | 20 | |
38cc26f9 | 21 | retries_times = [5 * 60, 5 * 60, 10 * 60, 10 * 60, 30 * 60, 60 * 60] |
4dd00642 MM |
22 | |
23 | def read_name_val(file): | |
dfff8bd5 MM |
24 | f = open(file) |
25 | r = {'_file': file[:-5], '_desc': file} | |
26 | rx = re.compile(r"^([^:]+)\s*:(.*)$") | |
8b63d7eb | 27 | for l in f: |
dfff8bd5 MM |
28 | if l == "END\n": |
29 | f.close() | |
30 | return r | |
31 | m = rx.search(l) | |
32 | if m: | |
33 | r[m.group(1)] = string.strip(m.group(2)) | |
34 | else: | |
35 | break | |
36 | f.close() | |
37 | return None | |
4dd00642 MM |
38 | |
39 | def scp_file(src, target): | |
115a41fc | 40 | global problems |
828e87a1 | 41 | f = os.popen("scp -v -B %s %s 2>&1 < /dev/null" % (src, target)) |
1c077aad AM |
42 | p = f.read() |
43 | ret = f.close() | |
44 | if ret: | |
1d17ddb1 | 45 | problems[src] = p |
1c077aad | 46 | return ret |
4dd00642 MM |
47 | |
48 | def copy_file(src, target): | |
dfff8bd5 MM |
49 | try: |
50 | shutil.copyfile(src, target) | |
51 | return 0 | |
52 | except: | |
115a41fc | 53 | global problems |
dfff8bd5 | 54 | exctype, value = sys.exc_info()[:2] |
87696e31 | 55 | problems[src] = "cannot copy file: %s" % traceback.format_exception_only(exctype, value) |
dfff8bd5 | 56 | return 1 |
4dd00642 | 57 | |
6db97676 | 58 | def rsync_file(src, target, host): |
115a41fc | 59 | global problems |
af279159 | 60 | |
dfff8bd5 | 61 | p = open(path.rsync_password_file, "r") |
af279159 | 62 | password = "" |
8b63d7eb | 63 | for l in p: |
dfff8bd5 MM |
64 | l = string.split(l) |
65 | if len(l) >= 2 and l[0] == host: | |
66 | password = l[1] | |
6db97676 | 67 | p.close() |
af279159 ER |
68 | |
69 | # NOTE: directing STDIN to /dev/null, does not make rsync to skip asking | |
70 | # password, it opens /dev/tty and still asks if password is needed and | |
71 | # missing, therefore we always set RSYNC_PASSWORD env var | |
72 | os.environ["RSYNC_PASSWORD"] = password | |
63f310aa | 73 | rsync = "rsync --verbose --archive --timeout=360 --contimeout=360" |
af279159 | 74 | f = os.popen("%s %s %s 2>&1" % (rsync, src, target)) |
1c077aad | 75 | p = f.read() |
1c077aad AM |
76 | ret = f.close() |
77 | if ret: | |
78 | problems[src] = p | |
af279159 | 79 | del os.environ["RSYNC_PASSWORD"]; |
1c077aad | 80 | return ret |
63319e0a | 81 | |
a43956d8 | 82 | def rsync_ssh_file(src, target): |
115a41fc | 83 | global problems |
2b80a862 | 84 | rsync = "rsync --verbose --archive --timeout=360 -e ssh" |
8a108792 | 85 | f = os.popen("%s %s %s 2>&1 < /dev/null" % (rsync, src, target)) |
1c077aad AM |
86 | p = f.read() |
87 | ret = f.close() | |
88 | if ret: | |
89 | problems[src] = p | |
90 | return ret | |
8a108792 | 91 | |
63319e0a | 92 | def post_file(src, url): |
115a41fc | 93 | global problems |
63319e0a AM |
94 | try: |
95 | f = open(src, 'r') | |
96 | data = f.read() | |
97 | f.close() | |
98 | req = urllib2.Request(url, data) | |
4dcdc5af | 99 | req.add_header('X-Filename', os.path.basename(src)) |
63319e0a | 100 | f = urllib2.urlopen(req) |
63319e0a AM |
101 | f.close() |
102 | except Exception, e: | |
115a41fc | 103 | problems[src] = e |
63319e0a | 104 | return e |
264be85c | 105 | return 0 |
63319e0a | 106 | |
4dd00642 | 107 | def send_file(src, target): |
115a41fc | 108 | global problems |
be3b9c0e AM |
109 | try: |
110 | log.notice("sending %s to %s (size %d bytes)" % (src, target, os.stat(src).st_size)) | |
111 | m = re.match('rsync://([^/]+)/.*', target) | |
112 | if m: | |
860792bf | 113 | return not rsync_file(src, target, host = m.group(1)) |
be3b9c0e | 114 | if target != "" and target[0] == '/': |
860792bf | 115 | return not copy_file(src, target) |
be3b9c0e AM |
116 | m = re.match('scp://([^@:]+@[^/:]+)(:|)(.*)', target) |
117 | if m: | |
860792bf | 118 | return not scp_file(src, m.group(1) + ":" + m.group(3)) |
be3b9c0e AM |
119 | m = re.match('ssh\+rsync://([^@:]+@[^/:]+)(:|)(.*)', target) |
120 | if m: | |
860792bf | 121 | return not rsync_ssh_file(src, m.group(1) + ":" + m.group(3)) |
c87a0ffa | 122 | m = re.match('(http|https)://.*', target) |
be3b9c0e | 123 | if m: |
860792bf | 124 | return not post_file(src, target) |
be3b9c0e AM |
125 | log.alert("unsupported protocol: %s" % target) |
126 | except OSError, e: | |
115a41fc | 127 | problems[src] = e |
38e23c91 | 128 | log.error("send_file(%s, %s): %s" % (src, target, e)) |
be3b9c0e AM |
129 | return False |
130 | return True | |
4dd00642 MM |
131 | |
132 | def maybe_flush_queue(dir): | |
dfff8bd5 MM |
133 | retry_delay = 0 |
134 | try: | |
9be34149 | 135 | f = open(dir + "/retry-at") |
dfff8bd5 MM |
136 | last_retry = int(string.strip(f.readline())) |
137 | retry_delay = int(string.strip(f.readline())) | |
138 | f.close() | |
139 | if last_retry + retry_delay > time.time(): | |
140 | return | |
9be34149 | 141 | os.unlink(dir + "/retry-at") |
dfff8bd5 MM |
142 | except: |
143 | pass | |
e6376553 | 144 | |
dfff8bd5 | 145 | status.push("flushing %s" % dir) |
4dd00642 | 146 | |
dfff8bd5 | 147 | if flush_queue(dir): |
9be34149 | 148 | f = open(dir + "/retry-at", "w") |
dfff8bd5 MM |
149 | if retry_delay in retries_times: |
150 | idx = retries_times.index(retry_delay) | |
151 | if idx < len(retries_times) - 1: idx += 1 | |
152 | else: | |
153 | idx = 0 | |
154 | f.write("%d\n%d\n" % (time.time(), retries_times[idx])) | |
155 | f.close() | |
4dd00642 | 156 | |
dfff8bd5 | 157 | status.pop() |
0ea52c57 | 158 | |
4dd00642 | 159 | def flush_queue(dir): |
dfff8bd5 MM |
160 | q = [] |
161 | os.chdir(dir) | |
162 | for f in glob.glob(dir + "/*.desc"): | |
163 | d = read_name_val(f) | |
164 | if d != None: q.append(d) | |
165 | def mycmp(x, y): | |
166 | rc = cmp(x['Time'], y['Time']) | |
fe60a597 | 167 | if rc == 0 and x.has_key('Type') and y.has_key('Type'): |
dfff8bd5 MM |
168 | return cmp(x['Type'], y['Type']) |
169 | else: | |
170 | return rc | |
171 | q.sort(mycmp) | |
e6376553 | 172 | |
dfff8bd5 | 173 | error = None |
be3b9c0e AM |
174 | # copy of q |
175 | remaining = q[:] | |
dfff8bd5 | 176 | for d in q: |
be3b9c0e | 177 | if not send_file(d['_file'], d['Target']): |
dfff8bd5 | 178 | error = d |
be3b9c0e | 179 | continue |
dfff8bd5 | 180 | if os.access(d['_file'] + ".info", os.F_OK): |
be3b9c0e | 181 | if not send_file(d['_file'] + ".info", d['Target'] + ".info"): |
dfff8bd5 | 182 | error = d |
be3b9c0e | 183 | continue |
36ca4e53 | 184 | os.unlink(d['_file'] + ".info") |
dfff8bd5 MM |
185 | os.unlink(d['_file']) |
186 | os.unlink(d['_desc']) | |
be3b9c0e | 187 | remaining.remove(d) |
e6376553 | 188 | |
dfff8bd5 MM |
189 | if error != None: |
190 | emails = {} | |
191 | emails[config.admin_email] = 1 | |
115a41fc | 192 | pr = "" |
0adcdbc2 | 193 | for src, msg in problems.items(): |
45eeec56 | 194 | pr = pr + "[src: %s]\n\n%s\n" % (src, msg) |
dfff8bd5 MM |
195 | for d in remaining: |
196 | if d.has_key('Requester'): | |
197 | emails[d['Requester']] = 1 | |
198 | e = emails.keys() | |
199 | m = mailer.Message() | |
e6376553 | 200 | m.set_headers(to = string.join(e, ", "), |
d7b0d9d2 | 201 | subject = "[%s] builder queue problem" % config.builder) |
dfff8bd5 | 202 | m.write("there were problems sending files from queue %s:\n" % dir) |
115a41fc | 203 | m.write("problems:\n") |
d9efe31a | 204 | m.write("%s\n" % pr) |
dfff8bd5 | 205 | m.send() |
115a41fc | 206 | log.error("error sending files from %s:\n%s\n" % (dir, pr)) |
dfff8bd5 | 207 | return 1 |
4dd00642 | 208 | |
dfff8bd5 | 209 | return 0 |
4dd00642 | 210 | |
115a41fc | 211 | problems = {} |
4dd00642 MM |
212 | |
213 | def main(): | |
dfff8bd5 MM |
214 | if lock.lock("sending-files", non_block = 1) == None: |
215 | return | |
032526d0 | 216 | init_conf() |
63319e0a | 217 | maybe_flush_queue(path.notify_queue_dir) |
dfff8bd5 MM |
218 | maybe_flush_queue(path.buildlogs_queue_dir) |
219 | maybe_flush_queue(path.ftp_queue_dir) | |
4dd00642 | 220 | |
e8ee9db8 | 221 | if __name__ == '__main__': |
dfff8bd5 | 222 | loop.run_loop(main) |