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