]> git.pld-linux.org Git - projects/pld-builder.new.git/blame - PLD_Builder/rpm_builder.py
- fix missing user
[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
135 # make neccessary files readable for builder user
136 # TODO: see if they really aren't readable for builder
137 for db in Packages Name Basenames Providename Pubkeys; do
138 db=/var/lib/rpm/$db
139 test -f $db && chmod a+r $db
140 done
141
142 # try to limit network access for builder account
143 /bin/setfacl -m u:builder:--- /etc/resolv.conf
144 """, 'root')
84c6175b 145
17f23d66 146def build_rpm(r, b):
dfff8bd5
MM
147 status.push("building %s" % b.spec)
148 b.log_line("request from: %s" % r.requester)
6ce49c66 149
5c91097f 150 if check_skip_build(r, b):
6ce49c66
AM
151 b.log_line("build skipped due to src builder request")
152 res = "SKIP_REQUESTED"
153 return res
154
dfff8bd5
MM
155 b.log_line("started at: %s" % time.asctime())
156 fetch_src(r, b)
157 b.log_line("installing srpm: %s" % b.src_rpm)
ffc633c5
ER
158 res = chroot.run("""
159 install -d rpm/SPECS rpm/SOURCES
160 rpm -Uhv %s
161 """ % b.src_rpm, logfile = b.logfile)
dfff8bd5
MM
162 chroot.run("rm -f %s" % b.src_rpm, logfile = b.logfile)
163 b.files = []
164 tmpdir = "/tmp/B." + b.b_id[0:6]
165 if res:
166 b.log_line("error: installing src rpm failed")
511ece79 167 res = "FAIL_SRPM_INSTALL"
deda9a51 168 else:
84c6175b 169 prepare_env()
dfff8bd5 170 chroot.run("install -m 700 -d %s" % tmpdir)
be264f26
ER
171
172 b.default_target(config.arch)
2e5736d2 173 rpmbuild_opt = "%s %s %s" % (b.target_string(), b.kernel_string(), b.bconds_string())
81c135f6 174 # check for build arch before filling BR
0dded0a1 175 cmd = "cd rpm/SPECS; TMPDIR=%s exec nice -n %s rpmbuild -bp --short-circuit --nodeps --define 'prep exit 0' %s %s" % \
81c135f6
ER
176 (tmpdir, config.nice, rpmbuild_opt, b.spec)
177 res = chroot.run(cmd, logfile = b.logfile)
4f2d26fb 178 if res:
511ece79 179 res = "UNSUPP"
a957e64f 180 b.log_line("error: build arch check (%s) failed" % cmd)
81c135f6
ER
181
182 if not res:
feb26777 183 if ("no-install-br" not in r.flags) and not install.uninstall_self_conflict(b):
511ece79 184 res = "FAIL_DEPS_UNINSTALL"
feb26777 185 if ("no-install-br" not in r.flags) and not install.install_br(r, b):
511ece79 186 res = "FAIL_DEPS_INSTALL"
73bdb36b 187 if not res:
1de1342f 188 max_jobs = max(min(int(os.sysconf('SC_NPROCESSORS_ONLN') + 1), config.max_jobs), 1)
85303822 189 if r.max_jobs > 0:
a1b28a50 190 max_jobs = max(min(config.max_jobs, r.max_jobs), 1)
0dded0a1 191 cmd = "echo build-id: %s; cd rpm/SPECS; TMPDIR=%s exec nice -n %s rpmbuild -bb --define '_smp_mflags -j%d' %s %s" % \
0e8fbf23 192 (r.id, tmpdir, config.nice, max_jobs, rpmbuild_opt, b.spec)
81c135f6 193 b.log_line("building RPM using: %s" % cmd)
efb3621d 194 begin_time = time.time()
81c135f6 195 res = chroot.run(cmd, logfile = b.logfile)
efb3621d 196 end_time = time.time()
8152253f 197 b.log_line("ended at: %s, done in %s" % (time.asctime(), datetime.timedelta(0, end_time - begin_time)))
4f2d26fb
AM
198 if res:
199 res = "FAIL"
81c135f6
ER
200 files = util.collect_files(b.logfile)
201 if len(files) > 0:
202 r.chroot_files.extend(files)
203 else:
204 b.log_line("error: No files produced.")
2b9e7381
AM
205 last_section = util.find_last_section(b.logfile)
206 if last_section == None:
207 res = "FAIL"
208 else:
209 res = "FAIL_%s" % last_section.upper()
81c135f6
ER
210 b.files = files
211
dfff8bd5
MM
212 chroot.run("rm -rf %s; cd rpm/SPECS; rpmbuild --nodeps --nobuild " \
213 "--clean --rmspec --rmsource %s" % \
214 (tmpdir, b.spec), logfile = b.logfile)
4e9e9dee 215 chroot.run("chmod -R u+rwX rpm/BUILD/*; rm -rf rpm/BUILD/*", logfile = b.logfile)
dfff8bd5
MM
216
217 def ll(l):
218 util.append_to(b.logfile, l)
e6376553 219
dfff8bd5 220 if b.files != []:
fd499dc1 221 rpm_cache_dir = config.rpm_cache_dir
e936beda 222 if "test-build" not in r.flags:
adc1235e 223 # NOTE: copying to cache dir doesn't mean that build failed, so ignore result
90d9480e 224 b.log_line("copy rpm files to cache_dir: %s" % rpm_cache_dir)
adc1235e 225 chroot.run(
fd499dc1
ER
226 "cp -f %s %s && poldek --mo=nodiff --mkidxz -s %s/" % \
227 (string.join(b.files), rpm_cache_dir, rpm_cache_dir),
228 logfile = b.logfile, user = "root"
229 )
e936beda 230 else:
fd499dc1 231 ll("test-build: not copying to " + rpm_cache_dir)
dfff8bd5
MM
232 ll("Begin-PLD-Builder-Info")
233 if "upgrade" in r.flags:
73bdb36b 234 b.upgraded = install.upgrade_from_batch(r, b)
dfff8bd5
MM
235 else:
236 ll("not upgrading")
237 ll("End-PLD-Builder-Info")
deda9a51 238
1051562e 239 for f in b.files:
dfff8bd5 240 local = r.tmp_dir + os.path.basename(f)
3e689257 241 chroot.cp(f, outfile = local, rm = True)
dfff8bd5 242 ftp.add(local)
1051562e 243
dfff8bd5
MM
244 def uploadinfo(b):
245 c="file:SRPMS:%s\n" % b.src_rpm
246 for f in b.files:
247 c=c + "file:ARCH:%s\n" % os.path.basename(f)
248 c=c + "END\n"
249 return c
3ea4b156 250
71a06b82 251 if config.gen_upinfo and b.files != [] and 'test-build' not in r.flags:
dfff8bd5
MM
252 fname = r.tmp_dir + b.src_rpm + ".uploadinfo"
253 f = open(fname, "w")
254 f.write(uploadinfo(b))
255 f.close()
256 ftp.add(fname, "uploadinfo")
257
258 status.pop()
259
260 return res
3ea4b156 261
17f23d66 262def handle_request(r):
dfff8bd5
MM
263 ftp.init(r)
264 buildlogs.init(r)
265 build.build_all(r, build_rpm)
266 report.send_report(r, is_src = False)
267 ftp.flush()
63319e0a 268 notify.send(r)
3ea4b156
MM
269
270def check_load():
dfff8bd5
MM
271 do_exit = 0
272 try:
273 f = open("/proc/loadavg")
274 if float(string.split(f.readline())[2]) > config.max_load:
275 do_exit = 1
276 except:
277 pass
278 if do_exit:
279 sys.exit(0)
3ea4b156 280
e8ee9db8 281def main_for(builder):
b8ec18af
AM
282 msg = ""
283
dfff8bd5 284 init_conf(builder)
dfff8bd5 285
dfff8bd5
MM
286 q = B_Queue(path.queue_file + "-" + config.builder)
287 q.lock(0)
288 q.read()
289 if q.requests == []:
290 q.unlock()
291 return
292 req = pick_request(q)
7b16924c 293 q.unlock()
dfff8bd5 294
91112237
AM
295 # high priority tasks have priority < 0, normal tasks >= 0
296 if req.priority >= 0:
b8ec18af
AM
297
298 # allow only one build in given builder at once
299 if not lock.lock("building-rpm-for-%s" % config.builder, non_block = 1):
300 return
301 # don't kill server
302 check_load()
303 # not more then job_slots builds at once
304 locked = 0
305 for slot in range(config.job_slots):
306 if lock.lock("building-rpm-slot-%d" % slot, non_block = 1):
307 locked = 1
308 break
309 if not locked:
310 return
311
312 # record fact that we got lock for this builder, load balancer
313 # will use it for fair-queuing
314 l = lock.lock("got-lock")
315 f = open(path.got_lock_file, "a")
316 f.write(config.builder + "\n")
317 f.close()
318 l.close()
319 else:
320 msg = "HIGH PRIORITY: "
e6376553 321
b8ec18af
AM
322 msg += "handling request %s (%d) for %s from %s, priority %s" \
323 % (req.id, req.no, config.builder, req.requester, req.priority)
dfff8bd5
MM
324 log.notice(msg)
325 status.push(msg)
326 handle_request(req)
327 status.pop()
328
329 def otherreqs(r):
330 if r.no==req.no:
331 return False
332 else:
333 return True
334
335 q = B_Queue(path.queue_file + "-" + config.builder)
336 q.lock(0)
337 q.read()
338 previouslen=len(q.requests)
339 q.requests=filter(otherreqs, q.requests)
340 if len(q.requests)<previouslen:
341 q.write()
342 q.unlock()
e6376553 343
e8ee9db8 344def main():
dfff8bd5 345 if len(sys.argv) < 2:
939af6d7 346 raise Exception, "fatal: need to have builder name as first arg"
dfff8bd5 347 return main_for(sys.argv[1])
e6376553 348
e8ee9db8 349if __name__ == '__main__':
dfff8bd5 350 loop.run_loop(main)
This page took 0.150527 seconds and 4 git commands to generate.