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