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