]> git.pld-linux.org Git - projects/pld-builder.new.git/blob - PLD_Builder/rpm_builder.py
- more interesting failure statuses.
[projects/pld-builder.new.git] / PLD_Builder / rpm_builder.py
1 # vi: encoding=utf-8 ts=8 sts=4 sw=4 et
2
3 import sys
4 import os
5 import atexit
6 import time
7 import string
8 import urllib
9
10 from config import config, init_conf
11 from bqueue import B_Queue
12 import lock
13 import util
14 import loop
15 import path
16 import status
17 import log
18 import chroot
19 import ftp
20 import buildlogs
21 import notify
22 import build
23 import report
24 import install
25
26 # *HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*
27 import socket
28
29 socket.myorigsocket=socket.socket
30
31 def mysocket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
32     s=socket.myorigsocket(family, type, proto)
33     s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
34     return s
35
36 socket.socket=mysocket
37 # *HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*
38
39 # this code is duplicated in srpm_builder, but we
40 # might want to handle some cases differently here
41 def pick_request(q):
42     def mycmp(r1, r2):
43         if r1.kind != 'group' or r2.kind != 'group':
44             raise Exception, "non-group requests"
45         pri_diff = cmp(r1.priority, r2.priority)
46         if pri_diff == 0:
47             return cmp(r1.time, r2.time)
48         else:
49             return pri_diff
50     q.requests.sort(mycmp)
51     ret = q.requests[0]
52     return ret
53
54 def fetch_src(r, b):
55     src_url = config.control_url + "/srpms/" + r.id + "/" + b.src_rpm
56     b.log_line("fetching %s" % src_url)
57     start = time.time()
58     good=False
59     while not good:
60         try:
61             good=True
62             f = urllib.urlopen(src_url)
63         except IOError, error:
64             if error[1][0] == 60 or error[1][0] == 110 or error[1][0] == -3 or error[1][0] == 111 or error[1][0] == 61:
65                 good=False
66                 b.log_line("unable to connect... trying again")
67             else:
68                 f = urllib.urlopen(src_url) # So we get the exception logged :)
69
70     o = chroot.popen("cat > %s" % b.src_rpm, mode = "w")
71
72     try:
73         bytes = util.sendfile(f, o)
74     except IOError, e:
75         b.log_line("error: unable to write to `%s': %s" % (b.src_rpm, e))
76         raise
77
78     f.close()
79     o.close()
80     t = time.time() - start
81     if t == 0:
82         b.log_line("fetched %d bytes" % bytes)
83     else:
84         b.log_line("fetched %d bytes, %.1f K/s" % (bytes, bytes / 1024.0 / t))
85
86 def prepare_env():
87     chroot.run("test ! -f /proc/uptime && mount /proc", 'root')
88     chroot.run("test ! -e /dev/full && mknod /dev/full c 1 7 && chmod 666 /dev/full", 'root')
89     chroot.run("test ! -e /dev/null && mknod /dev/null c 1 3 && chmod 666 /dev/null", 'root')
90     chroot.run("test ! -e /dev/random && mknod /dev/random c 1 8 && chmod 644 /dev/random", 'root')
91     chroot.run("test ! -e /dev/urandom && mknod /dev/urandom c 1 9 && chmod 644 /dev/urandom", 'root')
92     chroot.run("test ! -e /dev/zero && mknod /dev/zero c 1 5 && chmod 666 /dev/zero", 'root')
93
94 def build_rpm(r, b):
95     status.push("building %s" % b.spec)
96     b.log_line("request from: %s" % r.requester)
97     b.log_line("started at: %s" % time.asctime())
98     fetch_src(r, b)
99     b.log_line("installing srpm: %s" % b.src_rpm)
100     res = chroot.run("rpm -U %s" % b.src_rpm, logfile = b.logfile)
101     chroot.run("rm -f %s" % b.src_rpm, logfile = b.logfile)
102     b.files = []
103     tmpdir = "/tmp/B." + b.b_id[0:6]
104     if res:
105         b.log_line("error: installing src rpm failed")
106         res = "FAIL_SRPM_INSTALL"
107     else:
108         prepare_env()
109         chroot.run("install -m 700 -d %s" % tmpdir)
110
111         b.default_target(config.arch)
112         rpmbuild_opt = "%s %s %s" % (b.target_string(), b.kernel_string(), b.bconds_string())
113         # check for build arch before filling BR
114         cmd = "cd rpm/SPECS; TMPDIR=%s nice -n %s rpmbuild -bp --short-circuit --nodeps --define 'prep exit 0' %s %s" % \
115             (tmpdir, config.nice, rpmbuild_opt, b.spec)
116         res = chroot.run(cmd, logfile = b.logfile)
117         if res:
118             res = "UNSUPP"
119             b.log_line("error: build arch check (%s) failed" % cmd)
120
121         if not res:
122             if ("no-install-br" not in r.flags) and not install.uninstall_self_conflict(b):
123                 res = "FAIL_DEPS_UNINSTALL"
124             if ("no-install-br" not in r.flags) and not install.install_br(r, b):
125                 res = "FAIL_DEPS_INSTALL"
126             if not res:
127                 cmd = "cd rpm/SPECS; TMPDIR=%s nice -n %s rpmbuild -bb %s %s" % \
128                             (tmpdir, config.nice, rpmbuild_opt, b.spec)
129                 b.log_line("building RPM using: %s" % cmd)
130                 res = chroot.run(cmd, logfile = b.logfile)
131                 if res:
132                     res = "FAIL"
133                 files = util.collect_files(b.logfile)
134                 if len(files) > 0:
135                     r.chroot_files.extend(files)
136                 else:
137                     b.log_line("error: No files produced.")
138                     last_section = util.find_last_section(b.logfile)
139                     if last_section == None:
140                         res = "FAIL"
141                     else:
142                         res = "FAIL_%s" % last_section.upper()
143                 b.files = files
144
145     chroot.run("rm -rf %s; cd rpm/SPECS; rpmbuild --nodeps --nobuild " \
146                          "--clean --rmspec --rmsource %s" % \
147                          (tmpdir, b.spec), logfile = b.logfile)
148     chroot.run("rm -rf $HOME/rpm/BUILD/*")
149
150     def ll(l):
151         util.append_to(b.logfile, l)
152  
153     if b.files != []:
154         rpm_cache_dir = config.rpm_cache_dir
155         if "test-build" not in r.flags:
156             # XXX missing error check!
157             b.log_line("copy rpm files to cache_dir=%s" % rpm_cache_dir)
158             res = chroot.run(
159                     "cp -f %s %s && poldek --mo=nodiff --mkidxz -s %s/" % \
160                         (string.join(b.files), rpm_cache_dir, rpm_cache_dir),
161                      logfile = b.logfile, user = "root"
162             )
163         else:
164             ll("test-build: not copying to " + rpm_cache_dir)
165         ll("Begin-PLD-Builder-Info")
166         if "upgrade" in r.flags:
167             b.upgraded = install.upgrade_from_batch(r, b)
168         else:
169             ll("not upgrading")
170         ll("End-PLD-Builder-Info")
171
172     for f in b.files:
173         local = r.tmp_dir + os.path.basename(f)
174         chroot.cp(f, outfile = local, rm = True)
175         ftp.add(local)
176
177     def uploadinfo(b):
178         c="file:SRPMS:%s\n" % b.src_rpm
179         for f in b.files:
180             c=c + "file:ARCH:%s\n" % os.path.basename(f)
181         c=c + "END\n"
182         return c
183
184     if config.gen_upinfo and b.files != [] and 'test-build' not in r.flags:
185         fname = r.tmp_dir + b.src_rpm + ".uploadinfo"
186         f = open(fname, "w")
187         f.write(uploadinfo(b))
188         f.close()
189         ftp.add(fname, "uploadinfo")
190
191     status.pop()
192
193     return res
194
195 def handle_request(r):
196     ftp.init(r)
197     buildlogs.init(r)
198     build.build_all(r, build_rpm)
199     report.send_report(r, is_src = False)
200     ftp.flush()
201     notify.send(r)
202
203 def check_load():
204     do_exit = 0
205     try:
206         f = open("/proc/loadavg")
207         if float(string.split(f.readline())[2]) > config.max_load:
208             do_exit = 1
209     except:
210         pass
211     if do_exit:
212         sys.exit(0)
213
214 def main_for(builder):
215     msg = ""
216
217     init_conf(builder)
218
219     q = B_Queue(path.queue_file + "-" + config.builder)
220     q.lock(0)
221     q.read()
222     if q.requests == []:
223         q.unlock()
224         return
225     req = pick_request(q)
226     q.unlock()
227
228     # high priority tasks have priority < 0, normal tasks >= 0
229     if req.priority >= 0:
230
231         # allow only one build in given builder at once
232         if not lock.lock("building-rpm-for-%s" % config.builder, non_block = 1):
233             return
234         # don't kill server
235         check_load()
236         # not more then job_slots builds at once
237         locked = 0
238         for slot in range(config.job_slots):
239             if lock.lock("building-rpm-slot-%d" % slot, non_block = 1):
240                 locked = 1
241                 break
242         if not locked:
243             return
244
245         # record fact that we got lock for this builder, load balancer
246         # will use it for fair-queuing
247         l = lock.lock("got-lock")
248         f = open(path.got_lock_file, "a")
249         f.write(config.builder + "\n")
250         f.close()
251         l.close()
252     else:
253         msg = "HIGH PRIORITY: "
254     
255     msg += "handling request %s (%d) for %s from %s, priority %s" \
256             % (req.id, req.no, config.builder, req.requester, req.priority)
257     log.notice(msg)
258     status.push(msg)
259     handle_request(req)
260     status.pop()
261
262     def otherreqs(r):
263         if r.no==req.no:
264             return False
265         else:
266             return True
267
268     q = B_Queue(path.queue_file + "-" + config.builder)
269     q.lock(0)
270     q.read()
271     previouslen=len(q.requests)
272     q.requests=filter(otherreqs, q.requests)
273     if len(q.requests)<previouslen:
274         q.write()
275     q.unlock()
276     
277 def main():
278     if len(sys.argv) < 2:
279         raise Exception, "fatal: need to have builder name as first arg"
280     return main_for(sys.argv[1])
281     
282 if __name__ == '__main__':
283     loop.run_loop(main)
This page took 0.544363 seconds and 4 git commands to generate.