]> git.pld-linux.org Git - projects/pld-builder.new.git/blame - PLD_Builder/rpm_builder.py
Use errno from exception reason since error.errno is mostly 0.
[projects/pld-builder.new.git] / PLD_Builder / rpm_builder.py
CommitLineData
dfff8bd5
MM
1# vi: encoding=utf-8 ts=8 sts=4 sw=4 et
2
3ea4b156
MM
3import sys
4import os
5import atexit
6import time
8152253f 7import datetime
deda9a51 8import string
3458d3ee 9import urllib
10764658 10import urllib2
3ea4b156
MM
11
12from config import config, init_conf
13from bqueue import B_Queue
3ea4b156
MM
14import lock
15import util
3f446d8f 16import loop
3ea4b156
MM
17import path
18import status
19import log
20import chroot
21import ftp
e2cad913 22import buildlogs
59ce7cd6 23import notify
17f23d66
MM
24import build
25import report
73bdb36b 26import install
3ea4b156 27
53989cf3
MM
28# *HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*
29import socket
30
31socket.myorigsocket=socket.socket
32
33def mysocket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
dfff8bd5
MM
34 s=socket.myorigsocket(family, type, proto)
35 s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
36 return s
53989cf3
MM
37
38socket.socket=mysocket
39# *HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*HACK*
40
3ea4b156
MM
41# this code is duplicated in srpm_builder, but we
42# might want to handle some cases differently here
43def pick_request(q):
dfff8bd5
MM
44 def mycmp(r1, r2):
45 if r1.kind != 'group' or r2.kind != 'group':
939af6d7 46 raise Exception, "non-group requests"
dfff8bd5
MM
47 pri_diff = cmp(r1.priority, r2.priority)
48 if pri_diff == 0:
49 return cmp(r1.time, r2.time)
50 else:
bbed4c4d 51 return pri_diff
dfff8bd5
MM
52 q.requests.sort(mycmp)
53 ret = q.requests[0]
54 return ret
3ea4b156 55
5c91097f 56def check_skip_build(r, b):
6ce49c66 57 src_url = config.control_url + "/srpms/" + r.id + "/skipme"
79141e52 58 good = False
9143deab 59 b.log_line("checking if we should skip the build")
6ce49c66
AM
60 while not good:
61 try:
aa90a502
AM
62 headers = { 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }
63 req = urllib2.Request(url=src_url, headers=headers)
64 f = urllib2.urlopen(req)
29526c54 65 good = True
f1d6a788 66 except urllib2.HTTPError, error:
70f0fc62 67 return False
10764658
AM
68 except urllib2.URLError, error:
69 # see errno.h
70f0fc62
ER
70 try:
71 errno = error.errno
72 except AttributeError:
73 # python 2.4
74 errno = error.reason[0]
75
76 if errno in [-3, 60, 61, 110, 111]:
6ce49c66
AM
77 b.log_line("unable to connect... trying again")
78 continue
79 else:
80 return False
29526c54 81 f.close()
b8acd415 82 return True
6ce49c66
AM
83 return False
84
17f23d66 85def fetch_src(r, b):
3458d3ee 86 src_url = config.control_url + "/srpms/" + r.id + "/" + urllib.quote(b.src_rpm)
dfff8bd5
MM
87 b.log_line("fetching %s" % src_url)
88 start = time.time()
29526c54 89 good = False
dfff8bd5
MM
90 while not good:
91 try:
aa90a502
AM
92 headers = { 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }
93 req = urllib2.Request(url=src_url, headers=headers)
94 f = urllib2.urlopen(req)
29526c54 95 good = True
f1d6a788
AM
96 except urllib2.HTTPError, error:
97 # fail in a way where cron job will retry
deddea65 98 msg = "unable to fetch url %s, http code: %d" % (src_url, error.code)
f1d6a788 99 b.log_line(msg)
2a7e772f
AM
100 queue_time = time.time() - r.time
101 # 6 hours
02bb30ae 102 if error.code != 404 or (queue_time >= 0 and queue_time < (6 * 60 * 60)):
2a7e772f
AM
103 raise IOError, msg
104 else:
ec3ee349 105 msg = "in queue for more than 6 hours, download failing"
2a7e772f
AM
106 b.log_line(msg)
107 return False
10764658 108 except urllib2.URLError, error:
c3fb6bc6 109 errno = error.reason.errno
70f0fc62
ER
110
111 if errno in [-3, 60, 61, 110, 111]:
deddea65 112 b.log_line("unable to connect to %s... trying again" % (src_url))
e0226a74 113 continue
dfff8bd5 114 else:
85d03545 115 raise
dfff8bd5
MM
116
117 o = chroot.popen("cat > %s" % b.src_rpm, mode = "w")
9e89ce60
AM
118
119 try:
120 bytes = util.sendfile(f, o)
121 except IOError, e:
00a1db68 122 b.log_line("error: unable to write to `%s': %s" % (b.src_rpm, e))
9e89ce60
AM
123 raise
124
dfff8bd5
MM
125 f.close()
126 o.close()
127 t = time.time() - start
128 if t == 0:
129 b.log_line("fetched %d bytes" % bytes)
130 else:
131 b.log_line("fetched %d bytes, %.1f K/s" % (bytes, bytes / 1024.0 / t))
3ea4b156 132
266325ca 133def prepare_env(logfile = None):
3cf6c853 134 chroot.run("""
efb9c5f7 135 test ! -f /proc/uptime && mount /proc 2>/dev/null
3cf6c853
ER
136 test ! -c /dev/full && rm -f /dev/full && mknod -m 666 /dev/full c 1 7
137 test ! -c /dev/null && rm -f /dev/null && mknod -m 666 /dev/null c 1 3
138 test ! -c /dev/random && rm -f /dev/random && mknod -m 644 /dev/random c 1 8
139 test ! -c /dev/urandom && rm -f /dev/urandom && mknod -m 644 /dev/urandom c 1 9
140 test ! -c /dev/zero && rm -f /dev/zero && mknod -m 666 /dev/zero c 1 5
141
cfbb8475 142 # need entry for "/" in mtab, for diskspace() to work in rpm
4a8b119a 143 [ -z $(awk '$2 == "/" {print $1; exit}' /etc/mtab) ] && mount -f -t rootfs rootfs /
cfbb8475 144
3cf6c853
ER
145 # make neccessary files readable for builder user
146 # TODO: see if they really aren't readable for builder
147 for db in Packages Name Basenames Providename Pubkeys; do
148 db=/var/lib/rpm/$db
149 test -f $db && chmod a+r $db
150 done
151
152 # try to limit network access for builder account
153 /bin/setfacl -m u:builder:--- /etc/resolv.conf
266325ca 154 """, 'root', logfile = logfile)
84c6175b 155
17f23d66 156def build_rpm(r, b):
266325ca
ER
157 packagename = b.get_package_name()
158 if not packagename:
4e14a9bc
ER
159 # should not really get here
160 b.log_line("error: No .spec not given of malformed: '%s'" % b.spec)
161 res = "FAIL_INTERNAL"
162 return res
163
4e14a9bc 164 status.push("building %s (%s)" % (b.spec, packagename))
dfff8bd5 165 b.log_line("request from: %s" % r.requester)
6ce49c66 166
5c91097f 167 if check_skip_build(r, b):
6ce49c66
AM
168 b.log_line("build skipped due to src builder request")
169 res = "SKIP_REQUESTED"
170 return res
171
dfff8bd5
MM
172 b.log_line("started at: %s" % time.asctime())
173 fetch_src(r, b)
174 b.log_line("installing srpm: %s" % b.src_rpm)
ffc633c5 175 res = chroot.run("""
4e14a9bc 176 set -ex;
266325ca 177 install -d %(topdir)s/{BUILD,RPMS};
242d917b 178 rpm -Uhv --nodeps %(rpmdefs)s %(src_rpm)s;
4e14a9bc
ER
179 rm -f %(src_rpm)s;
180 """ % {
266325ca 181 'topdir' : b._topdir,
4e14a9bc
ER
182 'rpmdefs' : b.rpmbuild_opts(),
183 'src_rpm' : b.src_rpm
184 }, logfile = b.logfile)
dfff8bd5 185 b.files = []
508a95ef 186
266325ca 187 tmpdir = b.tmpdir()
dfff8bd5
MM
188 if res:
189 b.log_line("error: installing src rpm failed")
511ece79 190 res = "FAIL_SRPM_INSTALL"
deda9a51 191 else:
84c6175b 192 prepare_env()
f83b11d5 193 chroot.run("set -x; install -m 700 -d %s" % tmpdir, logfile=b.logfile)
be264f26 194 b.default_target(config.arch)
81c135f6 195 # check for build arch before filling BR
4e14a9bc 196 cmd = "set -ex; TMPDIR=%(tmpdir)s exec nice -n %(nice)s " \
266325ca 197 "rpmbuild -bp --short-circuit --nodeps %(rpmdefs)s --define 'prep exit 0' %(topdir)s/%(spec)s" % {
4e14a9bc
ER
198 'tmpdir': tmpdir,
199 'nice' : config.nice,
266325ca 200 'topdir' : b._topdir,
4e14a9bc 201 'rpmdefs' : b.rpmbuild_opts(),
4e14a9bc
ER
202 'spec': b.spec,
203 }
81c135f6 204 res = chroot.run(cmd, logfile = b.logfile)
4f2d26fb 205 if res:
511ece79 206 res = "UNSUPP"
a957e64f 207 b.log_line("error: build arch check (%s) failed" % cmd)
81c135f6
ER
208
209 if not res:
feb26777 210 if ("no-install-br" not in r.flags) and not install.uninstall_self_conflict(b):
511ece79 211 res = "FAIL_DEPS_UNINSTALL"
feb26777 212 if ("no-install-br" not in r.flags) and not install.install_br(r, b):
511ece79 213 res = "FAIL_DEPS_INSTALL"
73bdb36b 214 if not res:
1de1342f 215 max_jobs = max(min(int(os.sysconf('SC_NPROCESSORS_ONLN') + 1), config.max_jobs), 1)
85303822 216 if r.max_jobs > 0:
a1b28a50 217 max_jobs = max(min(config.max_jobs, r.max_jobs), 1)
4e14a9bc 218 cmd = "set -ex; : build-id: %(r_id)s; TMPDIR=%(tmpdir)s exec nice -n %(nice)s " \
266325ca 219 "rpmbuild -bb --define '_smp_mflags -j%(max_jobs)d' %(rpmdefs)s %(topdir)s/%(spec)s" % {
4e14a9bc
ER
220 'r_id' : r.id,
221 'tmpdir': tmpdir,
222 'nice' : config.nice,
223 'rpmdefs' : b.rpmbuild_opts(),
266325ca 224 'topdir' : b._topdir,
4e14a9bc
ER
225 'max_jobs' : max_jobs,
226 'spec': b.spec,
227 }
81c135f6 228 b.log_line("building RPM using: %s" % cmd)
efb3621d 229 begin_time = time.time()
81c135f6 230 res = chroot.run(cmd, logfile = b.logfile)
efb3621d 231 end_time = time.time()
8152253f 232 b.log_line("ended at: %s, done in %s" % (time.asctime(), datetime.timedelta(0, end_time - begin_time)))
4f2d26fb
AM
233 if res:
234 res = "FAIL"
a73fab54 235 files = util.collect_files(b.logfile, basedir = b._topdir)
81c135f6
ER
236 if len(files) > 0:
237 r.chroot_files.extend(files)
238 else:
239 b.log_line("error: No files produced.")
2b9e7381
AM
240 last_section = util.find_last_section(b.logfile)
241 if last_section == None:
242 res = "FAIL"
243 else:
244 res = "FAIL_%s" % last_section.upper()
81c135f6
ER
245 b.files = files
246
b9b4ac17 247 # cleanup tmp and build files
4e14a9bc
ER
248 chroot.run("""
249 set -ex;
266325ca 250 chmod -R u+rwX %(topdir)s/BUILD;
b9b4ac17 251 rm -rf %(topdir)s/{tmp,BUILD}
266325ca 252 """ % {
266325ca 253 'topdir' : b._topdir,
266325ca 254 }, logfile = b.logfile)
dfff8bd5
MM
255
256 def ll(l):
257 util.append_to(b.logfile, l)
e6376553 258
dfff8bd5 259 if b.files != []:
fd499dc1 260 rpm_cache_dir = config.rpm_cache_dir
e936beda 261 if "test-build" not in r.flags:
adc1235e 262 # NOTE: copying to cache dir doesn't mean that build failed, so ignore result
90d9480e 263 b.log_line("copy rpm files to cache_dir: %s" % rpm_cache_dir)
adc1235e 264 chroot.run(
fd499dc1
ER
265 "cp -f %s %s && poldek --mo=nodiff --mkidxz -s %s/" % \
266 (string.join(b.files), rpm_cache_dir, rpm_cache_dir),
267 logfile = b.logfile, user = "root"
268 )
e936beda 269 else:
fd499dc1 270 ll("test-build: not copying to " + rpm_cache_dir)
dfff8bd5
MM
271 ll("Begin-PLD-Builder-Info")
272 if "upgrade" in r.flags:
73bdb36b 273 b.upgraded = install.upgrade_from_batch(r, b)
dfff8bd5
MM
274 else:
275 ll("not upgrading")
276 ll("End-PLD-Builder-Info")
deda9a51 277
1051562e 278 for f in b.files:
dfff8bd5 279 local = r.tmp_dir + os.path.basename(f)
3e689257 280 chroot.cp(f, outfile = local, rm = True)
dfff8bd5 281 ftp.add(local)
1051562e 282
b9b4ac17
ER
283 # cleanup all remains from this build
284 chroot.run("""
285 set -ex;
286 rm -rf %(topdir)s;
287 """ % {
288 'topdir' : b._topdir,
289 }, logfile = b.logfile)
290
dfff8bd5
MM
291 def uploadinfo(b):
292 c="file:SRPMS:%s\n" % b.src_rpm
293 for f in b.files:
294 c=c + "file:ARCH:%s\n" % os.path.basename(f)
295 c=c + "END\n"
296 return c
3ea4b156 297
71a06b82 298 if config.gen_upinfo and b.files != [] and 'test-build' not in r.flags:
dfff8bd5
MM
299 fname = r.tmp_dir + b.src_rpm + ".uploadinfo"
300 f = open(fname, "w")
301 f.write(uploadinfo(b))
302 f.close()
303 ftp.add(fname, "uploadinfo")
304
305 status.pop()
306
307 return res
3ea4b156 308
17f23d66 309def handle_request(r):
dfff8bd5
MM
310 ftp.init(r)
311 buildlogs.init(r)
312 build.build_all(r, build_rpm)
313 report.send_report(r, is_src = False)
314 ftp.flush()
63319e0a 315 notify.send(r)
3ea4b156
MM
316
317def check_load():
dfff8bd5
MM
318 do_exit = 0
319 try:
320 f = open("/proc/loadavg")
321 if float(string.split(f.readline())[2]) > config.max_load:
322 do_exit = 1
323 except:
324 pass
325 if do_exit:
326 sys.exit(0)
3ea4b156 327
e8ee9db8 328def main_for(builder):
b8ec18af
AM
329 msg = ""
330
dfff8bd5 331 init_conf(builder)
dfff8bd5 332
dfff8bd5
MM
333 q = B_Queue(path.queue_file + "-" + config.builder)
334 q.lock(0)
335 q.read()
336 if q.requests == []:
337 q.unlock()
338 return
339 req = pick_request(q)
7b16924c 340 q.unlock()
dfff8bd5 341
91112237
AM
342 # high priority tasks have priority < 0, normal tasks >= 0
343 if req.priority >= 0:
b8ec18af
AM
344
345 # allow only one build in given builder at once
346 if not lock.lock("building-rpm-for-%s" % config.builder, non_block = 1):
347 return
348 # don't kill server
349 check_load()
350 # not more then job_slots builds at once
351 locked = 0
352 for slot in range(config.job_slots):
353 if lock.lock("building-rpm-slot-%d" % slot, non_block = 1):
354 locked = 1
355 break
356 if not locked:
357 return
358
359 # record fact that we got lock for this builder, load balancer
360 # will use it for fair-queuing
361 l = lock.lock("got-lock")
362 f = open(path.got_lock_file, "a")
363 f.write(config.builder + "\n")
364 f.close()
365 l.close()
366 else:
367 msg = "HIGH PRIORITY: "
e6376553 368
b8ec18af
AM
369 msg += "handling request %s (%d) for %s from %s, priority %s" \
370 % (req.id, req.no, config.builder, req.requester, req.priority)
dfff8bd5
MM
371 log.notice(msg)
372 status.push(msg)
373 handle_request(req)
374 status.pop()
375
376 def otherreqs(r):
377 if r.no==req.no:
378 return False
379 else:
380 return True
381
382 q = B_Queue(path.queue_file + "-" + config.builder)
383 q.lock(0)
384 q.read()
385 previouslen=len(q.requests)
386 q.requests=filter(otherreqs, q.requests)
387 if len(q.requests)<previouslen:
388 q.write()
389 q.unlock()
e6376553 390
e8ee9db8 391def main():
dfff8bd5 392 if len(sys.argv) < 2:
939af6d7 393 raise Exception, "fatal: need to have builder name as first arg"
dfff8bd5 394 return main_for(sys.argv[1])
e6376553 395
e8ee9db8 396if __name__ == '__main__':
dfff8bd5 397 loop.run_loop(main)
This page took 0.171684 seconds and 4 git commands to generate.