]> TLD Linux GIT Repositories - tld-builder.git/blob - TLD_Builder/request_handler.py
- cleanup
[tld-builder.git] / TLD_Builder / request_handler.py
1 # vi: encoding=utf-8 ts=8 sts=4 sw=4 et
2
3 import email
4 import string
5 import time
6 import os
7 import sys
8 import fnmatch
9 import gpg
10 import request
11 import log
12 import path
13 import util
14 import wrap
15 import status
16 from acl import acl
17 from blacklist import blacklist
18 from lock import lock
19 from bqueue import B_Queue
20 from config import config, init_conf
21 from mailer import Message
22
23 def check_double_id(id):
24     id_nl = id + "\n"
25
26     ids = open(path.processed_ids_file)
27     for i in ids:
28         if i == id_nl:
29             # FIXME: security email here?
30             log.alert("request %s already processed" % id)
31             return 1
32     ids.close()
33
34     ids = open(path.processed_ids_file, "a")
35     ids.write(id_nl)
36     ids.close()
37
38     return 0
39
40 def handle_group(r, user):
41     lockf = None
42     def fail_mail(msg):
43         if len(r.batches) >= 1:
44             spec = r.batches[0].spec
45         else:
46             spec = "None.spec"
47         log.error("%s: %s" % (spec, msg))
48         m = Message()
49         m.set_headers(to = r.requester_email, cc = config.builder_list)
50         m.set_headers(subject = "building %s failed" % spec)
51         m.write_line(msg)
52         m.send()
53
54     lockf = lock("request")
55     if check_double_id(r.id):
56         lockf.close()
57         return
58
59     try:
60         if (user.change_requester and r.requester):
61             user = acl.user_by_login(r.requester)
62     except KeyError:
63         r.requester += '/' + user.get_login()
64     else:
65         r.requester = user.get_login()
66         r.requester_email = user.mail_to()
67
68     for batch in r.batches:
69
70         if not user.can_do("src", config.builder, batch.branch):
71             fail_mail("user %s is not allowed to src:%s:%s" \
72                         % (user.get_login(), config.builder, batch.branch))
73             lockf.close()
74             return
75
76         if 'test-build' in r.flags and 'upgrade' in r.flags:
77             fail_mail("it's forbidden to upgrade from a test build")
78             lockf.close()
79             return
80
81         if "upgrade" in r.flags and not user.can_do("upgrade", config.builder, batch.branch):
82             fail_mail("user %s is not allowed to upgrade:%s:%s" \
83                         % (user.get_login(), config.builder, batch.branch))
84             lockf.close()
85             return
86
87         # src builder handles only special commands
88         if batch.is_command() and (batch.command in ["git pull"] or batch.command[:5] == "skip:"  or config.builder in batch.builders):
89             batch.expand_builders(config.binary_builders + [config.src_builder])
90         else:
91             batch.expand_builders(config.binary_builders)
92
93         if not batch.is_command() and config.builder in batch.builders:
94             batch.builders.remove(config.builder)
95
96         for bld in batch.builders:
97             batch.builders_status[bld] = '?'
98             batch.builders_status_time[bld] = time.time()
99             if bld not in config.binary_builders and bld != config.builder:
100                 fail_mail("I (src rpm builder '%s') do not handle binary builder '%s', only '%s'" % \
101                         (config.builder, bld, ' '.join(config.binary_builders)))
102                 lockf.close()
103                 return
104             if batch.is_command():
105                 if "no-chroot" in batch.command_flags:
106                     if not user.can_do("command-no-chroot", bld):
107                         fail_mail("user %s is not allowed to command-no-chroot:%s" \
108                                 % (user.get_login(), bld))
109                         lockf.close()
110                         return
111                 if not user.can_do("command", bld):
112                     fail_mail("user %s is not allowed to command:%s" \
113                                 % (user.get_login(), bld))
114                     lockf.close()
115                     return
116             elif not user.can_do("binary", bld, batch.branch):
117                 pkg = batch.spec
118                 if pkg.endswith(".spec"):
119                     pkg = pkg[:-5]
120                 if not user.can_do("binary-" + pkg, bld, batch.branch):
121                     fail_mail("user %s is not allowed to binary-%s:%s:%s" \
122                                 % (user.get_login(), pkg, bld, batch.branch))
123                     lockf.close()
124                     return
125             if not "test-build" in r.flags and not user.can_do("ready", bld, batch.branch):
126                 fail_mail("user %s is not allowed to send ready builds (ready:%s:%s)" \
127                      % (user.get_login(), bld, batch.branch))
128                 lockf.close()
129                 return
130
131             pkg = batch.spec
132             if pkg.endswith(".spec"):
133                 pkg = pkg[:-5]
134             if not "test-build" in r.flags and blacklist.package(pkg):
135                 fail_mail("package '%s' is blacklisted, only test-builds allowed" % pkg)
136                 lockf.close()
137                 return
138
139     r.priority = user.check_priority(r.priority,config.builder)
140     r.time = time.time()
141     log.notice("queued %s from %s" % (r.id, user.get_login()))
142     q = B_Queue(path.queue_file)
143     q.lock(0)
144     q.read()
145     q.add(r)
146     q.write()
147     q.unlock()
148     lockf.close()
149
150 def handle_notification(r, user):
151     if not user.can_do("notify", r.builder):
152         log.alert("user %s is not allowed to notify:%s" % (user.login, r.builder))
153     q = B_Queue(path.req_queue_file)
154     q.lock(0)
155     q.read()
156     not_fin = list(filter(lambda r: not r.is_done(), q.requests))
157     r.apply_to(q)
158     for r in not_fin:
159         if r.is_done():
160             util.clean_tmp(path.srpms_dir + '/' + r.id)
161     now = time.time()
162     def leave_it(r):
163         # for ,,done'' set timeout to 4d
164         if r.is_done() and r.time + 4 * 24 * 60 * 60 < now:
165             return False
166         # and for not ,,done'' set it to 20d
167         if r.time + 20 * 24 * 60 * 60 < now:
168             util.clean_tmp(path.srpms_dir + '/' + r.id)
169             return False
170         return True
171     q.requests = list(filter(leave_it, q.requests))
172     q.write()
173     q.dump(path.queue_stats_file)
174     q.dump_html(path.queue_html_stats_file)
175     q.write_signed(path.req_queue_signed_file)
176     q.unlock()
177
178 def handle_request(req, filename = None):
179     if req == '':
180         log.alert('Empty body received. Filename: %s' % filename)
181         return False
182
183     keys = gpg.get_keys(req)
184     (em, body) = gpg.verify_sig(req)
185     if not em:
186         log.alert("Invalid signature, missing/untrusted key. Keys in gpg batch: '%s'" % keys)
187         return False
188     user = acl.user_by_email(em)
189     if user == None:
190         # FIXME: security email here
191         log.alert("'%s' not in acl. Keys in gpg batch: '%s'" % (em, keys))
192         return False
193
194     acl.set_current_user(user)
195     status.push("request from %s" % user.login)
196     r = request.parse_request(body)
197     if r.kind == 'group':
198         handle_group(r, user)
199     elif r.kind == 'notification':
200         handle_notification(r, user)
201     else:
202         msg = "%s: don't know how to handle requests of this kind '%s'" \
203                         % (user.get_login(), r.kind)
204         log.alert(msg)
205         m = user.message_to()
206         m.set_headers(subject = "unknown request")
207         m.write_line(msg)
208         m.send()
209     status.pop()
210     return True
211
212 def handle_request_main(req, filename = None):
213     acl.try_reload()
214     blacklist.try_reload()
215     init_conf("src")
216     status.push("handling email request")
217     ret = handle_request(req, filename = filename)
218     status.pop()
219     return ret
220
221 def main():
222     sys.exit(not handle_request_main(sys.stdin.read()))
223
224 if __name__ == '__main__':
225     wrap.wrap(main)