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