]> TLD Linux GIT Repositories - tld-builder.git/blob - PLD_Builder/request_handler.py
- from https://github.com/pld-linux/pld-builder.new
[tld-builder.git] / PLD_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 StringIO
8 import sys
9 import fnmatch
10
11 import gpg
12 import request
13 import log
14 import path
15 import util
16 import wrap
17 import status
18 from acl import acl
19 from lock import lock
20 from bqueue import B_Queue
21 from config import config, init_conf
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.xreadlines():
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 = user.message_to()
49         m.set_headers(subject = "building %s failed" % spec)
50         m.write_line(msg)
51         m.send()
52
53     lockf = lock("request")
54     if check_double_id(r.id):
55         lockf.close()
56         return
57
58     for batch in r.batches:
59
60         if not user.can_do("src", config.builder, batch.branch):
61             fail_mail("user %s is not allowed to src:%s:%s" \
62                         % (user.get_login(), config.builder, batch.branch))
63             lockf.close()
64             return
65
66         if 'test-build' in r.flags and 'upgrade' in r.flags:
67             fail_mail("it's forbidden to upgrade from a test build")
68             lockf.close()
69             return
70
71         if "upgrade" in r.flags and not user.can_do("upgrade", config.builder, batch.branch):
72             fail_mail("user %s is not allowed to upgrade:%s:%s" \
73                         % (user.get_login(), config.builder, batch.branch))
74             lockf.close()
75             return
76
77         # src builder handles only special commands
78         if batch.is_command() and (batch.command in ["git pull"] or batch.command[:5] == "skip:"  or config.builder in batch.builders):
79             batch.expand_builders(config.binary_builders + [config.src_builder])
80         else:
81             batch.expand_builders(config.binary_builders)
82
83         if not batch.is_command() and config.builder in batch.builders:
84             batch.builders.remove(config.builder)
85
86         for bld in batch.builders:
87             batch.builders_status[bld] = '?'
88             batch.builders_status_time[bld] = time.time()
89             if bld not in config.binary_builders and bld != config.builder:
90                 fail_mail("I (src rpm builder '%s') do not handle binary builder '%s', only '%s'" % \
91                         (config.builder, bld, string.join(config.binary_builders)))
92                 lockf.close()
93                 return
94             if batch.is_command():
95                 if "no-chroot" in batch.command_flags:
96                     if not user.can_do("command-no-chroot", bld):
97                         fail_mail("user %s is not allowed to command-no-chroot:%s" \
98                                 % (user.get_login(), bld))
99                         lockf.close()
100                         return
101                 if not user.can_do("command", bld):
102                     fail_mail("user %s is not allowed to command:%s" \
103                                 % (user.get_login(), bld))
104                     lockf.close()
105                     return
106             elif not user.can_do("binary", bld, batch.branch):
107                 pkg = batch.spec
108                 if pkg.endswith(".spec"):
109                     pkg = pkg[:-5]
110                 if not user.can_do("binary-" + pkg, bld, batch.branch):
111                     fail_mail("user %s is not allowed to binary-%s:%s:%s" \
112                                 % (user.get_login(), pkg, bld, batch.branch))
113                     lockf.close()
114                     return
115
116     r.priority = user.check_priority(r.priority,config.builder)
117     r.requester = user.get_login()
118     r.requester_email = user.mail_to()
119     r.time = time.time()
120     log.notice("queued %s from %s" % (r.id, user.get_login()))
121     q = B_Queue(path.queue_file)
122     q.lock(0)
123     q.read()
124     q.add(r)
125     q.write()
126     q.unlock()
127     lockf.close()
128
129 def handle_notification(r, user):
130     if not user.can_do("notify", r.builder):
131         log.alert("user %s is not allowed to notify:%s" % (user.login, r.builder))
132     q = B_Queue(path.req_queue_file)
133     q.lock(0)
134     q.read()
135     not_fin = filter(lambda (r): not r.is_done(), q.requests)
136     r.apply_to(q)
137     for r in not_fin:
138         if r.is_done():
139             util.clean_tmp(path.srpms_dir + '/' + r.id)
140     now = time.time()
141     def leave_it(r):
142         # for ,,done'' set timeout to 4d
143         if r.is_done() and r.time + 4 * 24 * 60 * 60 < now:
144             return False
145         # and for not ,,done'' set it to 20d
146         if r.time + 20 * 24 * 60 * 60 < now:
147             util.clean_tmp(path.srpms_dir + '/' + r.id)
148             return False
149         return True
150     q.requests = filter(leave_it, q.requests)
151     q.write()
152     q.dump(path.queue_stats_file)
153     q.dump_html(path.queue_html_stats_file)
154     q.write_signed(path.req_queue_signed_file)
155     q.unlock()
156
157 def handle_request(req, filename = None):
158     if req == '':
159         log.alert('Empty body received. Filename: %s' % filename)
160         return False
161
162     keys = gpg.get_keys(req)
163     (em, body) = gpg.verify_sig(req)
164     if not em:
165         log.alert("Invalid signature, missing/untrusted key. Keys in gpg batch: '%s'" % keys)
166         return False
167     user = acl.user_by_email(em)
168     if user == None:
169         # FIXME: security email here
170         log.alert("'%s' not in acl. Keys in gpg batch: '%s'" % (em, keys))
171         return False
172
173     acl.set_current_user(user)
174     status.push("request from %s" % user.login)
175     r = request.parse_request(body)
176     if r.kind == 'group':
177         handle_group(r, user)
178     elif r.kind == 'notification':
179         handle_notification(r, user)
180     else:
181         msg = "%s: don't know how to handle requests of this kind '%s'" \
182                         % (user.get_login(), r.kind)
183         log.alert(msg)
184         m = user.message_to()
185         m.set_headers(subject = "unknown request")
186         m.write_line(msg)
187         m.send()
188     status.pop()
189     return True
190
191 def handle_request_main(req, filename = None):
192     acl.try_reload()
193     init_conf("src")
194     status.push("handling email request")
195     ret = handle_request(req, filename = filename)
196     status.pop()
197     return ret
198
199 def main():
200     sys.exit(not handle_request_main(sys.stdin.read()))
201
202 if __name__ == '__main__':
203     wrap.wrap(main)