]> git.pld-linux.org Git - projects/pld-builder.new.git/blob - PLD_Builder/rpm_builder.py
Fail if src.rpm file cannot be downloaded.
[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                 raise
69         http_code = f.getcode()
70         if http_code != 200:
71             b.log_line("unable to fetch file, http code: %d" % http_code)
72             raise
73
74     o = chroot.popen("cat > %s" % b.src_rpm, mode = "w")
75
76     try:
77         bytes = util.sendfile(f, o)
78     except IOError, e:
79         b.log_line("error: unable to write to `%s': %s" % (b.src_rpm, e))
80         raise
81
82     f.close()
83     o.close()
84     t = time.time() - start
85     if t == 0:
86         b.log_line("fetched %d bytes" % bytes)
87     else:
88         b.log_line("fetched %d bytes, %.1f K/s" % (bytes, bytes / 1024.0 / t))
89
90 def prepare_env():
91     chroot.run("test ! -f /proc/uptime && mount /proc", 'root')
92     chroot.run("test ! -e /dev/full && mknod /dev/full c 1 7 && chmod 666 /dev/full", 'root')
93     chroot.run("test ! -e /dev/null && mknod /dev/null c 1 3 && chmod 666 /dev/null", 'root')
94     chroot.run("test ! -e /dev/random && mknod /dev/random c 1 8 && chmod 644 /dev/random", 'root')
95     chroot.run("test ! -e /dev/urandom && mknod /dev/urandom c 1 9 && chmod 644 /dev/urandom", 'root')
96     chroot.run("test ! -e /dev/zero && mknod /dev/zero c 1 5 && chmod 666 /dev/zero", 'root')
97     # try to limit network access for builder account
98     chroot.run("/bin/setfacl -m u:builder:--- /etc/resolv.conf", 'root')
99
100 def build_rpm(r, b):
101     status.push("building %s" % b.spec)
102     b.log_line("request from: %s" % r.requester)
103     b.log_line("started at: %s" % time.asctime())
104     fetch_src(r, b)
105     b.log_line("installing srpm: %s" % b.src_rpm)
106     res = chroot.run("rpm -U %s" % b.src_rpm, logfile = b.logfile)
107     chroot.run("rm -f %s" % b.src_rpm, logfile = b.logfile)
108     b.files = []
109     tmpdir = "/tmp/B." + b.b_id[0:6]
110     if res:
111         b.log_line("error: installing src rpm failed")
112         res = "FAIL_SRPM_INSTALL"
113     else:
114         prepare_env()
115         chroot.run("install -m 700 -d %s" % tmpdir)
116
117         b.default_target(config.arch)
118         rpmbuild_opt = "%s %s %s" % (b.target_string(), b.kernel_string(), b.bconds_string())
119         # check for build arch before filling BR
120         cmd = "cd rpm/SPECS; TMPDIR=%s nice -n %s rpmbuild -bp --short-circuit --nodeps --define 'prep exit 0' %s %s" % \
121             (tmpdir, config.nice, rpmbuild_opt, b.spec)
122         res = chroot.run(cmd, logfile = b.logfile)
123         if res:
124             res = "UNSUPP"
125             b.log_line("error: build arch check (%s) failed" % cmd)
126
127         if not res:
128             if ("no-install-br" not in r.flags) and not install.uninstall_self_conflict(b):
129                 res = "FAIL_DEPS_UNINSTALL"
130             if ("no-install-br" not in r.flags) and not install.install_br(r, b):
131                 res = "FAIL_DEPS_INSTALL"
132             if not res:
133                 max_jobs = max(min(int(os.sysconf('SC_NPROCESSORS_ONLN') * 1.5), config.max_jobs), 1)
134                 if r.max_jobs > 0:
135                     max_jobs = max(min(config.max_jobs, r.max_jobs), 1)
136                 cmd = "cd rpm/SPECS; TMPDIR=%s nice -n %s rpmbuild -bb --define '_smp_mflags -j%d' %s %s" % \
137                             (tmpdir, config.nice, max_jobs, rpmbuild_opt, b.spec)
138                 b.log_line("building RPM using: %s" % cmd)
139                 begin_time = time.time()
140                 res = chroot.run(cmd, logfile = b.logfile)
141                 end_time = time.time()
142                 b.log_line("ended at: %s, done in %s" % (time.asctime(), time.strftime("%Hh %Mm %Ss", time.gmtime(end_time - begin_time))))
143                 if res:
144                     res = "FAIL"
145                 files = util.collect_files(b.logfile)
146                 if len(files) > 0:
147                     r.chroot_files.extend(files)
148                 else:
149                     b.log_line("error: No files produced.")
150                     last_section = util.find_last_section(b.logfile)
151                     if last_section == None:
152                         res = "FAIL"
153                     else:
154                         res = "FAIL_%s" % last_section.upper()
155                 b.files = files
156
157     chroot.run("rm -rf %s; cd rpm/SPECS; rpmbuild --nodeps --nobuild " \
158                          "--clean --rmspec --rmsource %s" % \
159                          (tmpdir, b.spec), logfile = b.logfile)
160     chroot.run("rm -rf $HOME/rpm/BUILD/*")
161
162     def ll(l):
163         util.append_to(b.logfile, l)
164  
165     if b.files != []:
166         rpm_cache_dir = config.rpm_cache_dir
167         if "test-build" not in r.flags:
168             # NOTE: copying to cache dir doesn't mean that build failed, so ignore result
169             b.log_line("copy rpm files to cache_dir: %s" % rpm_cache_dir)
170             chroot.run(
171                     "cp -f %s %s && poldek --mo=nodiff --mkidxz -s %s/" % \
172                         (string.join(b.files), rpm_cache_dir, rpm_cache_dir),
173                      logfile = b.logfile, user = "root"
174             )
175         else:
176             ll("test-build: not copying to " + rpm_cache_dir)
177         ll("Begin-PLD-Builder-Info")
178         if "upgrade" in r.flags:
179             b.upgraded = install.upgrade_from_batch(r, b)
180         else:
181             ll("not upgrading")
182         ll("End-PLD-Builder-Info")
183
184     for f in b.files:
185         local = r.tmp_dir + os.path.basename(f)
186         chroot.cp(f, outfile = local, rm = True)
187         ftp.add(local)
188
189     def uploadinfo(b):
190         c="file:SRPMS:%s\n" % b.src_rpm
191         for f in b.files:
192             c=c + "file:ARCH:%s\n" % os.path.basename(f)
193         c=c + "END\n"
194         return c
195
196     if config.gen_upinfo and b.files != [] and 'test-build' not in r.flags:
197         fname = r.tmp_dir + b.src_rpm + ".uploadinfo"
198         f = open(fname, "w")
199         f.write(uploadinfo(b))
200         f.close()
201         ftp.add(fname, "uploadinfo")
202
203     status.pop()
204
205     return res
206
207 def handle_request(r):
208     ftp.init(r)
209     buildlogs.init(r)
210     build.build_all(r, build_rpm)
211     report.send_report(r, is_src = False)
212     ftp.flush()
213     notify.send(r)
214
215 def check_load():
216     do_exit = 0
217     try:
218         f = open("/proc/loadavg")
219         if float(string.split(f.readline())[2]) > config.max_load:
220             do_exit = 1
221     except:
222         pass
223     if do_exit:
224         sys.exit(0)
225
226 def main_for(builder):
227     msg = ""
228
229     init_conf(builder)
230
231     q = B_Queue(path.queue_file + "-" + config.builder)
232     q.lock(0)
233     q.read()
234     if q.requests == []:
235         q.unlock()
236         return
237     req = pick_request(q)
238     q.unlock()
239
240     # high priority tasks have priority < 0, normal tasks >= 0
241     if req.priority >= 0:
242
243         # allow only one build in given builder at once
244         if not lock.lock("building-rpm-for-%s" % config.builder, non_block = 1):
245             return
246         # don't kill server
247         check_load()
248         # not more then job_slots builds at once
249         locked = 0
250         for slot in range(config.job_slots):
251             if lock.lock("building-rpm-slot-%d" % slot, non_block = 1):
252                 locked = 1
253                 break
254         if not locked:
255             return
256
257         # record fact that we got lock for this builder, load balancer
258         # will use it for fair-queuing
259         l = lock.lock("got-lock")
260         f = open(path.got_lock_file, "a")
261         f.write(config.builder + "\n")
262         f.close()
263         l.close()
264     else:
265         msg = "HIGH PRIORITY: "
266     
267     msg += "handling request %s (%d) for %s from %s, priority %s" \
268             % (req.id, req.no, config.builder, req.requester, req.priority)
269     log.notice(msg)
270     status.push(msg)
271     handle_request(req)
272     status.pop()
273
274     def otherreqs(r):
275         if r.no==req.no:
276             return False
277         else:
278             return True
279
280     q = B_Queue(path.queue_file + "-" + config.builder)
281     q.lock(0)
282     q.read()
283     previouslen=len(q.requests)
284     q.requests=filter(otherreqs, q.requests)
285     if len(q.requests)<previouslen:
286         q.write()
287     q.unlock()
288     
289 def main():
290     if len(sys.argv) < 2:
291         raise Exception, "fatal: need to have builder name as first arg"
292     return main_for(sys.argv[1])
293     
294 if __name__ == '__main__':
295     loop.run_loop(main)
This page took 0.109263 seconds and 4 git commands to generate.