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